Spring Boot整合Jersey打包Jar运行时出现文件路径找不到错误求助
这个问题我之前也碰到过,核心原因是Jersey默认的packages()包扫描机制依赖文件系统路径访问,但Spring Boot生成的可执行Fat Jar是把编译后的类嵌套在BOOT-INF/classes下的,普通文件操作没法直接访问Jar内部的路径,所以抛出了FileNotFoundException。
下面给出几个可行的解决方案:
方案一:利用Spring上下文扫描注册Jersey资源类
既然Spring本身能很好地处理Fat Jar里的类加载,我们可以借助Spring的ApplicationContext来扫描带有@Path注解的端点类,然后手动注册到Jersey中:
修改你的JerseyConfig类,注入Spring上下文并替换原有的packages()调用:
package tech.aabo.celulascontentas.config; import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.server.ServerProperties; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; import javax.ws.rs.ApplicationPath; import javax.ws.rs.Path; @Component @ApplicationPath("/api") public class JerseyConfig extends ResourceConfig { // 注入Spring的ApplicationContext public JerseyConfig(ApplicationContext context) { register(JacksonJaxbJsonProvider.class); // 扫描所有带有@Path注解的Bean并注册到Jersey context.getBeansWithAnnotation(Path.class).values().forEach(this::register); property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true); } }
这个方法的优势是完全复用Spring的类加载机制,不会有Jar内部路径访问的问题,同时保证所有Jersey端点都会被正确注册。
方案二:使用Jersey的类加载器适配扫描(适用于Spring Boot 1.5.x)
如果你不想依赖Spring上下文,也可以给packages()方法指定当前的类加载器,让Jersey用类加载器来扫描资源而不是文件系统:
修改JerseyConfig的构造方法:
public JerseyConfig() { register(JacksonJaxbJsonProvider.class); // 指定类加载器进行包扫描 packages(JerseyConfig.class.getClassLoader(), "tech.aabo.celulascontentas.endpoint"); property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true); }
不过这个方法在部分Spring Boot 1.5.x版本中可能仍有兼容问题,优先推荐方案一。
方案三:升级Spring Boot版本(长期解决方案)
你的项目使用的是Spring Boot 1.5.9.RELEASE,这个版本已经比较老旧了。升级到2.x及以上版本后,Spring Boot对Jersey的Fat Jar扫描支持做了优化,默认就能处理这种场景,不需要修改太多代码。
升级时需要注意:
- 调整
spring-boot-starter-parent的版本号,比如2.7.15(稳定版) - 检查依赖兼容性,比如Jersey的版本会随Spring Boot自动管理,不需要手动指定
验证步骤
修改完成后,重新执行打包和运行命令:
mvnw package && java -jar target/celulascontentas-2.0.jar
如果一切正常,应用应该能顺利启动,不会再抛出路径找不到的异常。
内容的提问来源于stack exchange,提问作者HFR1994

