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>