SpringBoot 的 Maven plugin能够将 SpringBoot 应用打包为可执行的 jar 或 war 包,然后以通常的方式如 java -jar 来运行 SpringBoot 应用。Spring Boot Maven plugin 的 5个 Goals,最主要的就是能够将 mvn package 生成的软件包,再次打包为可执行的软件包,并将 mvn package 生成的软件包重命名为 *.original,springboot 打 jar 包,无法引用jar包里面的类,如何解决?

1、说明  

  SpringBoot 的 Maven 插件能够以 Maven 的方式为应用提供 SpringBoot 的支持,即为 SpringBoot 应用提供了执行 Maven 操作的可能。
  SpringBoot 的 Maven plugin能够将 SpringBoot 应用打包为可执行的 jar 或 war 包,然后以通常的方式如 java -jar 来运行 SpringBoot 应用。

2、对应插件

  Spring Boot Maven plugin 的 5个 Goals:

  • repackage,默认 goal。在 mvn package 之后,再次打包可执行的 jar/war,同时保留 mvn package 生成的 jar/war 为 .origin
  • run,运行 SpringBoot 应用
  • start,在 mvn integration-test 阶段,进行 SpringBoot 应用生命周期的管理
  • stop,在 mvn integration-test 阶段,进行 SpringBoot 应用生命周期的管理
  • build-info,生成 Actuator 使用的构建信息文件 build-info.properties

3、相关配置

对应 pom.xml 文件配置如下:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <mainClass>com.xxx.bs.SearchBsBootstrap</mainClass>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>repackage</goal>
            </goals>
        </execution>
    </executions>
</plugin>

4、repackage 说明

  Spring Boot Maven plugin的最主要 goal 就是 repackage,其在 Maven 的 package 生命周期阶段,能够将 mvn package 生成的软件包,再次打包为可执行的软件包,并将 mvn package 生成的软件包重命名为 *.original

  基于上述配置,对一个生成Jar软件包的项目执行如下命令。

mvn package spring-boot:repackage

   可以看到生成的两个jar文件,一个是 *.jar,另一个是 *.jar.original。

  在执行上述命令的过程中,Maven首先在package阶段打包生成*.jar文件;然后执行 spring-boot:repackage 重新打包,查找 Manifest 文件中配置的 Main-Class 属性,如下所示:

Manifest-Version: 1.0
Implementation-Title: search-bs
Implementation-Version: 0.1.0
Archiver-Version: Plexus Archiver
Built-By: sam
Implementation-Vendor-Id: org.springframework
Spring-Boot-Version: 2.1.2.RELEASE
Implementation-Vendor: Pivotal Software, Inc.
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: com.xxx.bs.SearchBsBootstrap
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Created-By: Apache Maven 3.6.0
Build-Jdk: 1.8.0_155

  注意,其中的 Main-Class 属性值为 org.springframework.boot.loader.JarLauncher;

  Start-Class属性值为 com.xxx.bs.SearchBsBootstrap

  其中 com.xxx.bs.SearchBsBootstrap 类中定义了 main() 方法,是程序的入口。

  通常,SpringBoot Maven plugin 会在打包过程中自动为 Manifest 文件设置 Main-Class 属性,事实上该属性究竟作用几何,还可以受 SpringBoot Maven plugin 的配置属性 layout 控制的,示例如下:

<plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <version>2.1.2.RELEASE</version>
  <configuration>
    <mainClass>${start-class}</mainClass>
    <layout>ZIP</layout>
  </configuration>
  <executions>
    <execution>
      <goals>
        <goal>repackage</goal>
      </goals>
    </execution>
  </executions>
</plugin>

注意,这里的layout属性值为 ZIP。

layout属性的值可以如下:

  • JAR,即通常的可执行jar

   Main-Class: org.springframework.boot.loader.JarLauncher

  • WAR,即通常的可执行 war,需要的servlet容器依赖位于WEB-INF/lib-provided

   Main-Class: org.springframework.boot.loader.warLauncher

  • ZIP,即 DIR,类似于JAR

   Main-Class: org.springframework.boot.loader.PropertiesLauncher

   MODULE,将所有的依赖库打包(scope为provided的除外),但是不打包Spring Boot的任何Launcher。

   NONE,将所有的依赖库打包,但是不打包Spring Boot的任何Launcher。

5、问题解答

springboot 打 jar 包,无法引用jar包里面的类,为什么?

问题描述:

  我的目录结构是一个父项目,下面有三个子项目client,common,server。client是对外提供的所有接口。在将这个项目打包之后,client的包对外提供。现在的问题是别的项目依赖了这个包之后无法引用里面的普通类。并且在打包时必须先compile才能install,不然install时client会报无法引用common中的类。
问题解答:

  因为使用了上面提到的 springboot 打包的方式,我们得明白这里的jar并不是普通意义上的 jar 包或者说不是Java中的公共类库,而是一个独立的Web应用。 实际上,这里的 jar 更应该是 war。只是由于 SpringBoot 的设计思想,应用使用了jar。 如果你的 jar 不是以服务的方式被访问,那么就完全不必使用 SpringBoot插件重新打包了,因为根本没有入口类,也不需要可执行的jar。所以针对这种情况需要视情况而定:

  1. 打的包如果是一个可运行的 jar 包,那么内部的公共类库需要抽离封装到应该是公共类库的 jar 包中,这个可运行的 jar 包或者是 war 包是对外提供服务的,是无法直接依赖引用的。

  2. 如果只是一个普通公共类库 jar 包,那么只需要将 pom 文件中使用 springboot repackage 打包方式修改为 maven 普通打包方式即可,即:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
        <source>8</source>
        <target>8</target>
    </configuration>
</plugin>