嵌入式Tomcat服务器添加jaxb-core依赖后触发FileNotFoundException的解决方法
问题背景
我正在开发一个基于JSP Servlet的嵌入式Tomcat应用,添加了指定的Maven依赖后,启动主程序时抛出了FileNotFoundException,提示找不到C:\Users\testuser\.m2\repository\com\sun\xml\bind\jaxb-core\2.2.11\jaxb-api.jar。
异常堆栈信息:
C:\Users\testuser.m2\repository\com\sun\xml\bind\jaxb-core\2.2.11\jaxb-api.jar
java.io.FileNotFoundException: C:\Users\testuser.m2\repository\com\sun\xml\bind\jaxb-core\2.2.11\jaxb-api.jar (系统找不到指定的文件)
at java.util.zip.ZipFile.open(Native Method)
at java.util.zip.ZipFile.(ZipFile.java:225)
at java.util.zip.ZipFile.(ZipFile.java:155)
at java.util.jar.JarFile.(JarFile.java:166)
at java.util.jar.JarFile.(JarFile.java:130)
at org.apache.tomcat.util.compat.JreCompat.jarFileNewInstance(JreCompat.java:221)
at org.apache.tomcat.util.scan.JarFileUrlJar.(JarFileUrlJar.java:65)
at org.apache.tomcat.util.scan.JarFactory.newInstance(JarFactory.java:49)
at org.apache.tomcat.util.scan.StandardJarScanner.process(StandardJarScanner.java:383)
at org.apache.tomcat.util.scan.StandardJarScanner.processURLs(StandardJarScanner.java:318)
at org.apache.tomcat.util.scan.StandardJarScanner.doScanClassPath(StandardJarScanner.java:270)
at org.apache.tomcat.util.scan.StandardJarScanner.scan(StandardJarScanner.java:233)
at org.apache.jasper.servlet.TldScanner.scanJars(TldScanner.java:262)
使用的Maven依赖(pom.xml):
<dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-core</artifactId> <version>2.2.11</version> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-core</artifactId> <version>${tomcat.version}</version> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <version>${tomcat.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency>
主应用启动代码:
package launch; import org.apache.catalina.LifecycleException; import org.apache.catalina.WebResourceRoot; import org.apache.catalina.core.StandardContext; import org.apache.catalina.startup.Tomcat; import org.apache.catalina.webresources.DirResourceSet; import org.apache.catalina.webresources.StandardRoot; import java.io.File; public class Main { public static void main(String[] args) throws Exception { String webappDirLocation = "src/main/webapp/"; Tomcat tomcat = new Tomcat(); //The port that we should run on can be set into an environment variable //Look for that variable and default to 8080 if it isn't there. String webPort = System.getenv("PORT"); if(webPort == null || webPort.isEmpty()) { webPort = "8080"; } tomcat.setPort(Integer.valueOf(webPort)); StandardContext ctx = (StandardContext) tomcat.addWebapp("", new File(webappDirLocation).getAbsolutePath()); System.out.println("configuring app with basedir: " + new File("./" + webappDirLocation).getAbsolutePath()); // Declare an alternative location for your "WEB-INF/classes" dir // Servlet 3.0 annotation will work File additionWebInfClasses = new File("target/classes"); WebResourceRoot resources = new StandardRoot(ctx); resources.addPreResources(new DirResourceSet(resources, "/WEB-INF/classes", additionWebInfClasses.getAbsolutePath(), "/")); ctx.setResources(resources); tomcat.enableNaming(); tomcat.getConnector(); try { tomcat.start(); } catch (LifecycleException e) { e.printStackTrace(); } tomcat.getServer().await(); } }
解决办法
我之前也碰到过这个问题,本质是Tomcat的JarScanner在扫描类路径时,错误地试图从jaxb-core的Jar包目录里找jaxb-api.jar——但实际上jaxb-api是一个独立的依赖,并不是jaxb-core的一部分。下面是几个可行的修复方案:
1. 显式添加jaxb-api依赖
既然Tomcat需要这个Jar,直接把它加入pom.xml即可,版本和jaxb-core保持一致:
<dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.2.11</version> </dependency>
添加后重新执行mvn clean install,Maven会自动下载这个依赖到本地仓库,Tomcat就能找到它了。
2. 让Tomcat跳过扫描jaxb-core相关Jar
如果你的应用不需要JAXB功能,或者不想额外添加依赖,可以配置Tomcat的JarScanner跳过扫描jaxb-core的Jar。修改你的Main类,在创建StandardContext之后添加以下代码:
// 获取当前上下文的Jar扫描器 StandardJarScanner jarScanner = (StandardJarScanner) ctx.getJarScanner(); // 设置跳过扫描jaxb-core的Jar jarScanner.setSkipJars("jaxb-core-2.2.11.jar"); // 或者用通配符匹配所有版本的jaxb-core // jarScanner.setSkipJars("jaxb-core-*.jar");
这样Tomcat就不会去扫描这个Jar,自然也就不会触发找不到文件的异常了。
3. 清理并重新下载Maven依赖
有时候是本地Maven仓库里的jaxb-core依赖损坏了,导致扫描时出错。执行以下命令清理本地仓库并重新拉取所有依赖:
mvn clean install -U
-U参数会强制Maven更新依赖,确保本地仓库里的Jar包都是完整且正确的。
4. 升级JAXB版本(可选)
2.2.11是比较老旧的版本,可能存在依赖结构的问题。你可以尝试升级到更高的稳定版本,比如2.3.x系列,这样能避免一些旧版本的兼容性问题:
<dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-core</artifactId> <version>2.3.8</version> </dependency> <dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.3.1</version> </dependency>
内容的提问来源于stack exchange,提问作者user12345

