从Spring Boot 1.3.7升级到1.4.0后,SIngle jar启动失败

时间:2016-08-10 13:51:00

标签: spring-boot spring-boot-maven-plugin

从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)

3 个答案:

答案 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);
            });
        };
    }
}