【问题标题】:Spring Boot JAR built with Maven using requiresUnpack not working使用 Maven 构建的 Spring Boot JAR 使用 requiresUnpack 不起作用
【发布时间】:2017-05-28 20:38:27
【问题描述】:

我想我遇到了以下问题Jersey doesn't always work with Spring Boot fat jars。解决方法应该是将POM 中的Jersey dependencies 设置为requiresUnpack

我的POM 看起来像这样:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>net.hagstrom</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jersey</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <requiresUnpack>
                        <dependency>
                            <groupId>org.glassfish.jersey.containers</groupId>
                            <artifactId>jersey-container-servlet</artifactId>
                        </dependency>
                        <dependency>
                            <groupId>org.glassfish.jersey.core</groupId>
                            <artifactId>jersey-client</artifactId>
                        </dependency>
                    </requiresUnpack>
                </configuration>
                <version>1.4.3.RELEASE</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

但是当我尝试运行使用mvn package 构建的 JAR 时,仍然出现以下错误:

2017-01-13 10:44:28.229 ERROR 9289 --- [ost-startStop-1] o.s.b.c.embedded.tomcat.TomcatStarter    : Error starting Tomcat context. Exception: org.springframework.beans.factory.UnsatisfiedDependencyException. Message: Error creating bean with name 'org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration': Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jerseyConfig' defined in URL [jar:file:/home/mikael/Dev/Java/Java%20Programs/springBootDemo/target/demo-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/net/hagstrom/JerseyConfig.class]: Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [net.hagstrom.JerseyConfig]: Constructor threw exception; nested exception is org.glassfish.jersey.server.internal.scanning.ResourceFinderException: java.io.FileNotFoundException: /home/mikael/Dev/Java/Java Programs/springBootDemo/target/demo-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes (No such file or directory)

运行我在 IDE 中使用 Artifacts 构建的 JAR 效果很好。

我的POM 或我使用 Maven 构建 JAR 的方式有问题吗?

【问题讨论】:

  • 我有相同版本的 spring-boot 和相同的 POM 配置(除了:不需要 requiresUnpack)。对我来说 /BOOT-INF/ 目录不是在 jar 中创建的,而是它的作品。你能检查 .jar 文件 datecreated first and next 用 gzip 打开它并查看结构吗?

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


【解决方案1】:

这可能已经修复了。我已经发布了一些与使用 Spring BootJersey 2Docker 创建 API 相关的博客文章,并使用 Swagger 记录它们,网址为:http://tech.asimio.net/2016/04/05/Microservices-using-Spring-Boot-Jersey-Swagger-and-Docker.htmlhttp://tech.asimio.net/2016/05/07/Documenting-multiple-REST-API-versions-using-Spring-Boot-Jersey-and-Swagger.html,均附有源代码,但我没有不需要unpackrepackage Jersey 2 依赖。

另一方面,当我在为另一个关于 Services Registration and Discovery using Spring Cloud, Eureka, Ribbon and Feign 的博客编写随附的源代码时,我正在集成 Spring BootJersey 1Jersey 1 没有 Spring Boot 启动器我做回想一下解决方案,解包 Jersey 1 依赖项,以便为该特定 API 服务创建多模块 Maven 项目。

【讨论】:

  • 在这些示例中您使用的是哪个版本的 Spring Boot?
  • @g3blv 涉及Jersey 2的教程使用Spring Boot 1.3.5.RELEASE和1.3.6.RELEASE。
【解决方案2】:

我发现了问题。

Spring Boot 1.4 改变了内部的 Jar 结构以方便 Spring Boot 引导过程。

https://github.com/spring-projects/spring-boot/issues/1468#issuecomment-267357809

你可以离开这个版本 1.4.3:

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

但是 spring-boot-jersey fat-jar 可以正常执行,需要像这样将插件版本降级到 1.3.8:

     <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>1.3.8.RELEASE</version>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

【讨论】:

  • 我的理解是,Spring Boot 1.4 中问题的解决方法是使用requiresUnpack,如下所述(github.com/spring-projects/spring-boot/issues/…)您引用的评论。
  • requiresUnpack 修复了不同类型的异常,例如:github.com/spring-projects/spring-boot/issues/1345 -> lib/jersey-client-1.11.jar(没有这样的文件或目录)。但是你有 /BOOT-INF/classes (没有这样的文件或目录)。这可以从 spring-boot-maven-plugin 修复(降级到 1.3.8)我有和你一样的例外,在@ootero 示例中使用了 1.3.8 版本的插件。为我解决这个问题。
【解决方案3】:

问题是 Jersey 无法扫描新的“fat boot jar”中的类。当您尝试使用 ResourceConfig 类的 packages("some.package.to.scan") 方法时会发生这种情况。

但是,您可以使用 Spring 类路径扫描工具实现相同的效果。这样你就可以像 config.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 注释的类(但由于扫描机制损坏,无法找到任何东西)。

(使用旧版本的引导插件也适用于我,但我尽量避免使用它。)

【讨论】:

    猜你喜欢
    • 2021-01-22
    • 2020-07-16
    • 2021-08-03
    • 2021-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-16
    • 2018-01-31
    相关资源
    最近更新 更多