从Spring Boot 1.3.7升级到1.4.0之后,我们再也无法使用Spring Boot Maven插件启动我们的应用程序作为单个jar构建。我们的应用程序是使用Jersey和Jetty的小型REST接口。我们使用Maven,我们的pom文件非常标准的Spring Boot。
我们仍然可以使用mvn spring-boot:run
从Eclipse中运行应用程序,但是当作为单个jar运行时,Jersey ResourceFinder
会抱怨它找不到.jar!/BOOT-INF/classes
。
当我解压缩jar时,文件夹BOOT-INF/classes
存在并包含预期的类和资源。
任何帮助表示感谢。
2016-08-10 14:58:31.162 ERROR 16071 --- [ main] o.s.boot.SpringApplication
: Application startup failed
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'jerseyConfig' defined in URL
[jar:file:/acmesource/acme/acme-core/acme-core-api/target/acme-core-api-0.1
SNAPSHOT.jar!/BOOT-INF/classes!/com/acme/core/api/JerseyConfig.class]: Bean
instantiation via constructor failed; nested exception is
org.springframework.beans.BeanInstantiationException: Failed to instantiate
[com.acme.core.api.JerseyConfig]: Constructor threw exception; nested
exception is
org.glassfish.jersey.server.internal.scanning.ResourceFinderException:
java.io.FileNotFoundException: /acmesource/acme/acme-core/acme-core
api/target/acme-core-api-0.1-SNAPSHOT.jar!/BOOT-INF/classes (No such file or directory)
答案 0 :(得分:8)
来自Spring Boot 1.4 release notes:
对可执行jar的布局的更改意味着limitation in Jersey's classpath scanning现在影响可执行jar文件 以及可执行的战争文件。要解决此问题,您希望由Jersey扫描的类应打包在jar中,并作为依赖项包含在
BOOT-INF/lib
中。然后,Spring Boot启动程序应为configured to unpack those jars on start up,以便Jersey可以扫描其内容。
答案 1 :(得分:2)
只是另一种解决方案:
虽然Jersey无法在新版本的胖启动jar中扫描你的类,但使用Spring类路径扫描工具可以达到同样的效果。这样,您可以类似于ResourceConfig.packages()
扫描包:
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
scanner.addIncludeFilter(new AnnotationTypeFilter(Provider.class));
scanner.addIncludeFilter(new AnnotationTypeFilter(Path.class));
config.registerClasses(scanner.findCandidateComponents("your.package.to.scan").stream()
.map(beanDefinition -> ClassUtils.resolveClassName(beanDefinition.getBeanClassName(), config.getClassLoader()))
.collect(Collectors.toSet()));
注意:请查看org.glassfish.jersey.server.internal.scanning.AnnotationAcceptingListener
的来源。这是库存解决方案,您可以看到它执行相同的操作:它会扫描使用@Path
或@Provider
注释的类(但由于扫描机制中断,因此无法找到任何内容)
顺便说一下lanwen发布的基于bean的方法可能更清楚了:)只需添加@Provider
即可。
答案 2 :(得分:1)
使用Spring Boot(+ Jersey 2),它看起来像是单独的配置类(实现个人资源注册):
@Configuration
public class RestBeansConfiguration {
private static final Logger LOG = LoggerFactory.getLogger(RestBeansConfiguration.class);
@Inject
private ApplicationContext appCtx;
@Bean
public ResourceConfigCustomizer jersey() {
return config -> {
LOG.info("Jersey resource classes found:");
appCtx.getBeansWithAnnotation(Path.class).forEach((name, resource) -> {
LOG.info(" -> {}", resource.getClass().getName());
config.register(resource);
});
};
}
}