8

从 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 运行时,JerseyResourceFinder抱怨它找不到.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)
4

3 回答 3

8

来自Spring Boot 1.4 发行说明

对可执行 jar 布局的更改意味着Jersey 类路径扫描的限制现在会影响可执行 jar 文件以及可执行 war 文件。要解决此问题,您希望由 Jersey 扫描的类应打包在一个 jar 中,并作为依赖项包含在BOOT-INF/lib. 然后应该将 Spring Boot 启动器配置为在启动时解压缩这些 jar,以便 Jersey 可以扫描它们的内容。

于 2016-08-10T14:50:44.893 回答
2

只是另一种解决方案:

尽管 Jersey 无法扫描新版本的 fat boot 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。这是常用的解决方案,您可以看到它的作用相同:它扫描用@Pathor注释的类@Provider(但由于扫描机制损坏,无法找到任何东西)。

顺便说一句,lanwen 发布的基于 bean 的方法可能更清晰 :) 也可以添加@Provider

于 2017-03-17T08:11:15.620 回答
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);
            });
        };
    }
}
于 2016-09-13T10:38:48.937 回答