Spring Boot Maven 插件 - 没有 BOOT-INF 目录

Posted

技术标签:

【中文标题】Spring Boot Maven 插件 - 没有 BOOT-INF 目录【英文标题】:Spring Boot Maven Plugin - No BOOT-INF directory 【发布时间】:2017-08-24 18:59:13 【问题描述】:

在 spring-boot-maven-plugin 的 1.3.8.RELEASE 版本和 1.4.0.RELEASE 版本之间 - 生成的包结构发生了变化(如果您提取 uber jar 文件) 1.3.8.RELEASE com、lib、META-INF 和 org 目录 1.4.0.RELEASE 有 BOOT-INF、META-INF 和 org 目录 基本上从 1.4.0.RELEASE 开始——所有的类和库都在 BOOT-INF 目录中。 因此 - 当您尝试在 Amazon Lambda 上运行 Spring Boot 项目时 - 它说找不到 jar,因为它无法读取新的 Spring Boot Uber jar 结构

我的问题是 - 在较新版本的 Spring Boot Maven 插件中是否有可能让它生成与版本 1.3.9.RELEASE 相同的结构的 uber jar?

我尝试了 maven-shade-plugin - 但这会导致其他问题

非常感谢任何帮助

谢谢 达米安

【问题讨论】:

【参考方案1】:

解决方案是在 pom.xml 文件中为插件添加 MODULE 布局

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <layout>MODULE</layout>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>repackage</goal>
            </goals>
        </execution>
    </executions>
</plugin>

【讨论】:

为什么没有人将其标记为正确答案。当我升级弹簧靴时,我遇到了类似的问题。对 docs.Spring 的描述感到困惑。添加这件作品。MODULE 如何为 build.gradle 做到这一点?我正在使用以下插件类路径“org.springframework.boot:spring-boot-gradle-plugin:1.4.2.RELEASE”,因此,我的胖罐子具有以下结构 BOOT-INF MATA-INF org.springframework.boot .loader 但我想要下面的结构 > META-INF 它说,未能执行目标 org.springframework.boot:spring-boot-maven-plugin:2.1.2.RELEASE:repackage (repackage) on project businessunit-service-businessunit: Unable to parse mojo org.springframework.boot 的配置:spring-boot-maven-plugin:2.1.2.RELEASE:repackage:无法将“模块”转换为枚举:没有枚举常量 org.springframework.boot.maven.RepackageMojo.LayoutType.MODULE - > [帮助1]【参考方案2】:

在我的情况下,我使用的是 spring boot 2.X,我在 maven-dependency-plugin 之后声明了 spring-boot-maven-plugin(我曾经在 Docker 中解压并创建分解的应用程序),它必须在解压之前,这是有道理的,它在spring boot maven插件执行之前被解包。下次我将在插件链中声明它的第一件事,为此浪费了一个多小时。希望它可以帮助某人。

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <mainClass>$spring.boot.mainClass</mainClass>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
                <execution>
                    <id>unpack</id>
                    <phase>package</phase>
                    <goals>
                        <goal>unpack</goal>
                    </goals>
                    <configuration>
                        <artifactItems>
                            <artifactItem>
                                <groupId>$project.groupId</groupId>
                                <artifactId>$project.artifactId</artifactId>
                                <version>$project.version</version>
                            </artifactItem>
                        </artifactItems>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

【讨论】:

我还通过将我的 maven-shade-plugin 声明放在 pom.xml 中的 spring-boot-maven-plugin 声明之前,让我的设置正常工作。生成的 shade jar 按预期在根目录中包含所有内容,而 Spring boot jar 按预期在 BOOT-INF 中包含所有内容。【参考方案3】:

上面的答案用

<layout>MODULE</layout>

不再起作用,这是因为 layout 元素在 Spring Boot 2.x 中已被弃用。 我正在使用 Spring Boot 2.0.x,我在 github 上发现了这条有用的评论:

在 Spring Boot 2.0 中删除了对模块布局的支持,在 1.5 中已弃用。不幸的是,Maven 插件文档的更新被遗漏了,所以我们可以使用这个问题来解决这个问题。您应该改用custom LayoutFactory。

但由于我不想实现 LayoutFactory,所以我尝试了下面的第二个解决方案,它实际上重新打包并创建了一个带有给定名称的分类器的额外 jar:

这是由于 Spring Boot 1.4 中可执行 jar 的布局发生了变化。应用程序类现在打包在 BOOT-INF/classes 中。 您的客户端模块依赖于重新打包的 web 模块的胖 jar。由于新布局意味着客户端模块无法再加载 Web 模块的类。如果你想使用你的 web 模块作为依赖,你应该配置 Boot 的重新打包以将分类器应用于 fat jar。例如:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                    <configuration>
                        <classifier>exec</classifier>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

这样做将允许其他模块依赖于原始 jar,该 jar 没有嵌入模块的依赖项,并且在 jar 的根目录下具有类。

一个原始罐子的结构与我想要的一样

com.my-package.foo.bar
META-INF

第二个分类器具有更新的结构,带有 BOOT-INF/ 等。

【讨论】:

非常感谢。很好的回答【参考方案4】:

对我来说,解决方案有点阴险......我将 spring-boot-maven-plugin 嵌套在 pluginManagement 下(见下文)。嗬!

令人讨厌的是,当我运行 mvn spring-boot:run 时,spring boot 运行良好,并运行 app!直到我们尝试部署到 PCF(作为 spring-boot JAR),我们才得到一个错误,表明二进制格式有问题....

<build>

  <!-- 
    DON'T DO THIS!! 
  -->
  <pluginManagement>

    <plugins>             
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <version>$spring.boot.version</version>            
        <executions>
            <execution>
                <goals>
                    <goal>repackage</goal>
                    <goal>build-info</goal>
                </goals>
            </execution>
        </executions>                        
      </plugin>                                     
    </plugins>

  </pluginManagement>

  <!-- 
    DO THIS INSTEAD!! 
  -->      
<plugins>

    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
      <version>$spring.boot.version</version>            
      <executions>
          <execution>
              <goals>
                  <goal>repackage</goal>
                  <goal>build-info</goal>
              </goals>
          </execution>
      </executions>                        
    </plugin>                         

  </plugins>

</build>

从 POM 中删除 pluginManagement 标记后,我现在将获得 ./BOOT-INF 结构。请记住,pluginManagement 通常用于父 pom 结构,您希望该插件的配置在其他模块中使用。

【讨论】:

【参考方案5】:

我使用的是 Gradle,而不是 Maven,这是我必须做的:

1- 在我的 build.gradle 中,我添加了 https://spring.io/guides/gs/spring-boot-Docker/ 中定义的以下属性。

buildscript 
    ...
    dependencies 
        ...
        classpath('gradle.plugin.com.palantir.gradle.docker:gradle-docker:0.13.0')
    


group = 'springio'

...
apply plugin: 'com.palantir.docker'

task unpack(type: Copy) 
    dependsOn bootJar
    from(zipTree(tasks.bootJar.outputs.files.singleFile))
    into("build/dependency")

docker 
    name "$project.group/$bootJar.baseName"
    copySpec.from(tasks.unpack.outputs).into("dependency")
    buildArgs(['DEPENDENCY': "dependency"])

2- 我的依赖文件夹没有被写入

ARG DEPENDENCY=target/dependency

相反,我将它放在另一个文件夹中,因此我在 Dockerfile 中更改了此属性:

ARG DEPENDENCY=build/dependency

这样我就成功构建了。

【讨论】:

以上是关于Spring Boot Maven 插件 - 没有 BOOT-INF 目录的主要内容,如果未能解决你的问题,请参考以下文章

Maven对原始Spring Boot JAR的依赖[重复]

Spring Boot Maven 插件 - spring-boot:run 和优雅关闭

找不到符号 - Spring Boot Maven 兄弟作为依赖

Maven插件系列之spring-boot-maven-plugin

使用 Spring Boot BOM 管理 Maven 插件版本

SpringBootPlugin ‘org.springframework.boot:spring-boot-maven-plugin:‘ not found