打包可执行档案

该插件可以创建包含应用程序所有依赖项的可执行档案(jar 文件和 war 文件),然后可以使用 java -jar 命令运行。

打包可执行档案由 repackage 目标执行,示例如下所示

<build>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
			<executions>
				<execution>
					<goals>
						<goal>repackage</goal>
					</goals>
				</execution>
			</executions>
		</plugin>
	</plugins>
</build>
repackage 目标不适合单独在命令行中使用,因为它作用于由 package 阶段生成的源 jar(或 war)。要在命令行上使用此目标,您必须包含 package 阶段:mvn package spring-boot:repackage
如果您正在使用 spring-boot-starter-parent,则此类执行已通过 repackage 执行 ID 进行预配置,因此只需添加插件定义即可。

上述示例会重新打包在 Maven 生命周期 package 阶段构建的 jarwar 档案,包括项目中定义的任何 provided 依赖。如果需要排除某些依赖项,可以使用 exclude 选项之一;更多详情请参阅依赖排除

默认情况下,原始(即不可执行的)artifact 会被重命名为 .original,但也可以使用自定义分类器保留原始 artifact。

目前不支持 maven-war-pluginoutputFileNameMapping 特性。

spring-boot-devtoolsspring-boot-docker-compose 模块默认会自动排除(您可以使用 excludeDevtoolsexcludeDockerCompose 属性控制)。为了使其在 war 打包中生效,必须将 spring-boot-devtoolsspring-boot-docker-compose 依赖项设置为 optional 或使用 provided 范围。

该插件会重写您的 manifest 文件,特别是管理 Main-ClassStart-Class 条目。如果默认值不适用,您必须在 Spring Boot 插件中配置这些值,而不是在 jar 插件中。manifest 文件中的 Main-Class 由 Spring Boot 插件的 layout 属性控制,示例如下所示

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

layout 属性默认值由档案类型(jarwar)决定。以下是可用的布局

  • JAR:常规可执行 JAR 布局。

  • WAR:可执行 WAR 布局。provided 依赖项放在 WEB-INF/lib-provided 中,以避免 war 部署到 servlet 容器时发生冲突。

  • ZIPDIR 的别名):类似于使用 PropertiesLauncherJAR 布局。

  • NONE:打包所有依赖项和项目资源。不包含引导加载器。

分层 Jar 或 War

重新打包的 jar 文件分别在 BOOT-INF/classesBOOT-INF/lib 中包含应用程序的类和依赖项。类似地,可执行 war 文件在 WEB-INF/classes 中包含应用程序的类,并在 WEB-INF/libWEB-INF/lib-provided 中包含依赖项。对于需要从 jar 或 war 内容构建 Docker 镜像的情况,能够进一步分离这些目录以便将它们写入不同的层是非常有用的。

分层档案使用与常规重新打包的 jar 或 war 相同的布局,但包含一个描述每个层的附加元数据文件。

默认情况下,定义了以下层

  • dependencies:适用于版本不包含 SNAPSHOT 的任何依赖项。

  • spring-boot-loader:适用于加载器类。

  • snapshot-dependencies:适用于版本包含 SNAPSHOT 的任何依赖项。

  • application:适用于本地模块依赖项、应用程序类和资源。

模块依赖项通过查看当前构建中的所有模块来识别。如果某个模块依赖项仅因已安装到 Maven 的本地缓存中且不属于当前构建而能够解析,则它将被识别为常规依赖项。

层的顺序很重要,因为它决定了当应用程序部分发生变化时,之前层被缓存的可能性。默认顺序是 dependenciesspring-boot-loadersnapshot-dependenciesapplication。最不可能更改的内容应首先添加,然后是更有可能更改的层。

默认情况下,重新打包的档案会包含 layers.idx 文件。要禁用此功能,可以按以下方式进行

<project>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<layers>
						<enabled>false</enabled>
					</layers>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

自定义分层配置

根据您的应用程序,您可能需要调整层的创建方式并添加新层。这可以通过一个单独的配置文件来完成,该文件应按如下方式注册

<project>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<layers>
						<enabled>true</enabled>
						<configuration>${project.basedir}/src/layers.xml</configuration>
					</layers>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

配置文件描述了如何将档案分成多个层以及这些层的顺序。以下示例显示了如何明确定义上述默认顺序

<layers xmlns="http://www.springframework.org/schema/boot/layers"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xsi:schemaLocation="http://www.springframework.org/schema/boot/layers
	                      https://www.springframework.org/schema/boot/layers/layers-3.4.xsd">
	<application>
		<into layer="spring-boot-loader">
			<include>org/springframework/boot/loader/**</include>
		</into>
		<into layer="application" />
	</application>
	<dependencies>
		<into layer="application">
			<includeModuleDependencies />
		</into>
		<into layer="snapshot-dependencies">
			<include>*:*:*SNAPSHOT</include>
		</into>
		<into layer="dependencies" />
	</dependencies>
	<layerOrder>
		<layer>dependencies</layer>
		<layer>spring-boot-loader</layer>
		<layer>snapshot-dependencies</layer>
		<layer>application</layer>
	</layerOrder>
</layers>

layers XML 格式定义了三个部分

  • <application> 块定义了应用程序类和资源应该如何分层。

  • <dependencies> 块定义了依赖项应该如何分层。

  • <layerOrder> 块定义了应该写入层的顺序。

嵌套的 <into> 块用于 <application><dependencies> 部分,用于为某个层声明内容。这些块按定义的顺序从上到下进行评估。任何未被较早块声明的内容仍可供后续块考虑。

<into> 块使用嵌套的 <include><exclude> 元素声明内容。<application> 部分使用 Ant 风格的路径匹配进行包含/排除表达式。<dependencies> 部分使用 group:artifact[:version] 模式。它还提供了 <includeModuleDependencies /><excludeModuleDependencies /> 元素,可用于包含或排除本地模块依赖项。

如果未定义 <include>,则考虑所有内容(未被较早块声明的内容)。

如果未定义 <exclude>,则不应用任何排除项。

查看上面的 <dependencies> 示例,我们可以看到第一个 <into> 将为 application.layer 声明所有模块依赖项。下一个 <into> 将为 snapshot-dependencies 层声明所有 SNAPSHOT 依赖项。最后一个 <into> 将为 dependencies 层声明剩余的所有内容(在本例中,即所有非 SNAPSHOT 依赖项)。

<application> 块具有类似的规则。首先为 spring-boot-loader 层声明 org/springframework/boot/loader/** 内容。然后为 application 层声明任何剩余的类和资源。

<into> 块的定义顺序通常与写入层的顺序不同。因此,必须始终包含 <layerOrder> 元素,并且它 必须 覆盖 <into> 块引用的所有层。

spring-boot:repackage

org.springframework.boot:spring-boot-maven-plugin:3.4.5

重新打包现有的 JAR 和 WAR 档案,以便可以使用 java -jar 从命令行执行它们。使用 layout=NONE 也可以简单地用于打包带有嵌套依赖项的 JAR(且没有主类,因此不可执行)。

必需参数

名称 类型 默认值

outputDirectory

File

${project.build.directory}

可选参数

名称 类型 默认值

attach

boolean

true

classifier

String

embeddedLaunchScript

File

embeddedLaunchScriptProperties

Properties

excludeDevtools

boolean

true

excludeDockerCompose

boolean

true

excludeGroupIds

String

excludes

List

executable

boolean

false

includeSystemScope

boolean

false

includeTools

boolean

true

includes

List

layers

Layers

layout

LayoutType

layoutFactory

LayoutFactory

loaderImplementation

LoaderImplementation

mainClass

String

outputTimestamp

String

${project.build.outputTimestamp}

requiresUnpack

List

skip

boolean

false

参数详情

attach

将重新打包的档案附加到要安装到本地 Maven 仓库或部署到远程仓库的 artifact。如果未配置分类器,它将替换正常的 jar 文件。如果配置了 classifier,使得正常 jar 和重新打包的 jar 不同,它将作为附加 artifact 与正常 jar 一同安装/部署。当该属性设置为 false 时,重新打包的档案将不会被安装或部署。

名称

attach

类型

boolean

默认值

true

用户属性

1.4.0

classifier

要添加到重新打包档案的分类器。如果未指定,主 artifact 将被重新打包档案替换。如果指定,该分类器也将用于确定要重新打包的源档案:如果已存在具有该分类器的 artifact,则将其用作源并被替换。如果不存在此类 artifact,则将使用主 artifact 作为源,并将重新打包的档案作为带有该分类器的附加 artifact 附加。附加 artifact 允许将其与原始 artifact 一同部署,更多详细信息请参阅Maven 文档

名称

classifier

类型

java.lang.String

默认值

用户属性

1.0.0

embeddedLaunchScript

如果 jar 是完全可执行的,要添加到 jar 前面的嵌入式启动脚本。如果未指定,将使用 Spring Boot 的默认脚本。

名称

embeddedLaunchScript

类型

java.io.File

默认值

用户属性

1.3.0

embeddedLaunchScriptProperties

应该在嵌入式启动脚本中展开的属性。

名称

embeddedLaunchScriptProperties

类型

java.util.Properties

默认值

用户属性

1.3.0

excludeDevtools

从重新打包的档案中排除 Spring Boot devtools。

名称

excludeDevtools

类型

boolean

默认值

true

用户属性

spring-boot.repackage.excludeDevtools

1.3.0

excludeDockerCompose

从重新打包的档案中排除 Spring Boot dev services。

名称

excludeDockerCompose

类型

boolean

默认值

true

用户属性

spring-boot.repackage.excludeDockerCompose

3.1.0

excludeGroupIds

要排除的 groupId 名称的逗号分隔列表(精确匹配)。

名称

excludeGroupIds

类型

java.lang.String

默认值

用户属性

spring-boot.excludeGroupIds

1.1.0

excludes

要排除的 artifact 定义集合。Exclude 元素定义了必需的 groupIdartifactId 组件以及可选的 classifier 组件。当配置为属性时,值应该是逗号分隔的,组件之间用冒号分隔:groupId:artifactId,groupId:artifactId:classifier

名称

excludes

类型

java.util.List

默认值

用户属性

spring-boot.excludes

1.1.0

executable

通过在 jar 文件前添加启动脚本,为 *nix 系统创建完全可执行的 jar。目前,某些工具不接受此格式,因此您可能并非总是能够使用此技术。例如,jar -xf 可能会静默地无法解压已设置为完全可执行的 jar 或 war。建议您仅在打算直接执行它时才启用此选项,而不是通过 java -jar 运行或部署到 servlet 容器。

名称

executable

类型

boolean

默认值

false

用户属性

1.3.0

includeSystemScope

包含系统范围的依赖项。

名称

includeSystemScope

类型

boolean

默认值

false

用户属性

1.4.0

includeTools

包含 JAR 工具。

名称

includeTools

类型

boolean

默认值

true

用户属性

3.3.0

includes

要包含的 artifact 定义集合。Include 元素定义了必需的 groupIdartifactId 组件以及可选的 classifier 组件。当配置为属性时,值应该是逗号分隔的,组件之间用冒号分隔:groupId:artifactId,groupId:artifactId:classifier

名称

includes

类型

java.util.List

默认值

用户属性

spring-boot.includes

1.2.0

layers

层配置,包含禁用层创建、排除层工具 jar 和提供自定义层配置文件的选项。

名称

layers

类型

org.springframework.boot.maven.Layers

默认值

用户属性

2.3.0

layout

档案类型(对应于依赖项在其中的布局方式)。可能的值包括 JARWARZIPDIRNONE。默认为基于档案类型的猜测值。

名称

layout

类型

org.springframework.boot.maven.AbstractPackagerMojo$LayoutType

默认值

用户属性

spring-boot.repackage.layout

1.0.0

layoutFactory

如果未设置显式布局,将用于创建可执行档案的布局工厂。第三方可以提供替代的布局实现。

名称

layoutFactory

类型

org.springframework.boot.loader.tools.LayoutFactory

默认值

用户属性

1.5.0

loaderImplementation

应该使用的加载器实现。

名称

loaderImplementation

类型

org.springframework.boot.loader.tools.LoaderImplementation

默认值

用户属性

3.2.0

mainClass

主类的名称。如果未指定,将使用找到的第一个包含 main 方法的编译类。

名称

mainClass

类型

java.lang.String

默认值

用户属性

1.0.0

outputDirectory

包含生成档案的目录。

名称

outputDirectory

类型

java.io.File

默认值

${project.build.directory}

用户属性

1.0.0

outputTimestamp

用于可重现输出档案条目的时间戳,格式可以是 ISO 8601 (yyyy-MM-dd’T’HH:mm:ssXXX) 或表示自 epoch 以来的秒数的 int 值。

名称

outputTimestamp

类型

java.lang.String

默认值

${project.build.outputTimestamp}

用户属性

2.3.0

requiresUnpack

必须从 uber jar 中解压才能运行的库列表。将每个库指定为带有 <groupId><artifactId><dependency>,它们将在运行时被解压。

名称

requiresUnpack

类型

java.util.List

默认值

用户属性

1.1.0

skip

跳过执行。

名称

skip

类型

boolean

默认值

false

用户属性

spring-boot.repackage.skip

1.2.0

示例

自定义分类器

默认情况下,repackage 目标将原始 artifact 替换为重新打包的 artifact。对于代表应用程序的模块来说,这是合理的行为,但如果您的模块被用作另一个模块的依赖项,您需要为重新打包的 artifact 提供一个分类器。这是因为应用程序类被打包在 BOOT-INF/classes 中,以便依赖模块无法加载重新打包 jar 中的类。

如果是这种情况,或者您希望保留原始 artifact 并使用不同的分类器附加重新打包的 artifact,请按以下示例配置插件

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

如果您正在使用 spring-boot-starter-parentrepackage 目标将自动在 id 为 repackage 的执行中运行。在此设置中,只需指定配置即可,示例如下所示

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

此配置将生成两个 artifact:原始 artifact 和由 repackage 目标生成的重新打包 artifact。两者都将透明地安装/部署。

如果您想以与替换主 artifact 相同的方式重新打包次要 artifact,也可以使用相同的配置。以下配置会安装/部署一个带有重新打包应用程序的、被分类为 task 的单个 artifact

<project>
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-jar-plugin</artifactId>
				<executions>
					<execution>
						<goals>
							<goal>jar</goal>
						</goals>
						<phase>package</phase>
						<configuration>
							<classifier>task</classifier>
						</configuration>
					</execution>
				</executions>
			</plugin>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<executions>
					<execution>
						<id>repackage</id>
						<goals>
							<goal>repackage</goal>
						</goals>
						<configuration>
							<classifier>task</classifier>
						</configuration>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>

由于 maven-jar-pluginspring-boot-maven-plugin 都运行在同一阶段,重要的是先定义 jar 插件(以便它在 repackage 目标之前运行)。同样,如果您正在使用 spring-boot-starter-parent,可以按如下方式简化

<project>
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-jar-plugin</artifactId>
				<executions>
					<execution>
						<id>default-jar</id>
						<configuration>
							<classifier>task</classifier>
						</configuration>
					</execution>
				</executions>
			</plugin>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<executions>
					<execution>
						<id>repackage</id>
						<configuration>
							<classifier>task</classifier>
						</configuration>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>

自定义名称

如果您需要重新打包的 jar 的本地名称与项目 artifactId 属性定义的名称不同,请使用标准的 finalName,示例如下所示

<project>
	<build>
		<finalName>my-app</finalName>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<executions>
					<execution>
						<id>repackage</id>
						<goals>
							<goal>repackage</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>

此配置将在 target/my-app.jar 中生成重新打包的 artifact。

本地重新打包 artifact

默认情况下,repackage 目标将原始 artifact 替换为可执行 artifact。如果您只需要部署原始 jar,但仍希望能够使用常规文件名运行应用程序,请按如下方式配置插件

<project>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<executions>
					<execution>
						<id>repackage</id>
						<goals>
							<goal>repackage</goal>
						</goals>
						<configuration>
							<attach>false</attach>
						</configuration>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>

此配置生成两个 artifact:原始 artifact 和由 repackage 目标生成的可执行 artifact。只有原始 artifact 会被安装/部署。

自定义布局

Spring Boot 使用定义在附加 jar 文件(作为构建插件的依赖项提供)中的自定义布局工厂重新打包此项目的 jar 文件

<project>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<executions>
					<execution>
						<id>repackage</id>
						<goals>
							<goal>repackage</goal>
						</goals>
						<configuration>
							<layoutFactory implementation="com.example.CustomLayoutFactory">
								<customProperty>value</customProperty>
							</layoutFactory>
						</configuration>
					</execution>
				</executions>
				<dependencies>
					<dependency>
						<groupId>com.example</groupId>
						<artifactId>custom-layout</artifactId>
						<version>0.0.1.BUILD-SNAPSHOT</version>
					</dependency>
				</dependencies>
			</plugin>
		</plugins>
	</build>
</project>

布局工厂作为 LayoutFactory(来自 spring-boot-loader-tools)的实现提供,在 pom 中明确指定。如果在插件 classpath 上只有一个自定义 LayoutFactory,并且它列在 META-INF/spring.factories 中,则无需在插件配置中显式设置它。

如果设置了显式布局,则始终忽略布局工厂。

依赖排除

默认情况下,repackagerun 目标都会包含项目中定义的任何 provided 依赖项。Spring Boot 项目应将 provided 依赖项视为运行应用程序所需的“容器”依赖项。一般来说,Spring Boot 项目不被用作依赖项,因此不太可能具有任何 optional 依赖项。当项目确实有 optional 依赖项时,repackagerun 目标也会包含它们。

其中一些依赖项可能完全不需要,应从可执行 JAR 中排除。为保持一致性,在运行应用程序时也不应包含它们。

有两种方法可以排除依赖项,使其不被打包或在运行时使用

  • 排除由 groupIdartifactId 标识的特定构件,如果需要,可选择带上 classifier

  • 排除属于给定 groupId 的任何构件。

以下示例排除 com.example:module1,且仅排除该构件

<project>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<excludes>
						<exclude>
							<groupId>com.example</groupId>
							<artifactId>module1</artifactId>
						</exclude>
					</excludes>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

此示例排除属于 com.example 组的任何构件

<project>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<excludeGroupIds>com.example</excludeGroupIds>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

JAR 工具

创建分层 JAR 或 WAR 时,spring-boot-jarmode-tools JAR 将作为依赖项添加到您的归档中。在类路径中包含此 JAR,您可以以特殊模式启动应用程序,该模式允许引导代码运行与您的应用程序完全不同的内容,例如,提取分层内容的程序。如果您希望排除此依赖项,可以按以下方式操作

<project>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<includeTools>false</includeTools>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

自定义分层配置

默认设置将依赖项分为 snapshot 和非 snapshot,但是,您可能有更复杂的规则。例如,您可能希望在专用分层中隔离项目的公司特定依赖项。以下 layers.xml 配置显示了这样一种设置

<layers xmlns="http://www.springframework.org/schema/boot/layers"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xsi:schemaLocation="http://www.springframework.org/schema/boot/layers
						  https://www.springframework.org/schema/boot/layers/layers-3.4.xsd">
	<application>
		<into layer="spring-boot-loader">
			<include>org/springframework/boot/loader/**</include>
		</into>
		<into layer="application" />
	</application>
	<dependencies>
		<into layer="snapshot-dependencies">
			<include>*:*:*SNAPSHOT</include>
		</into>
		<into layer="company-dependencies">
			<include>com.acme:*</include>
		</into>
		<into layer="dependencies"/>
	</dependencies>
	<layerOrder>
		<layer>dependencies</layer>
		<layer>spring-boot-loader</layer>
		<layer>snapshot-dependencies</layer>
		<layer>company-dependencies</layer>
		<layer>application</layer>
	</layerOrder>
</layers>

以上配置创建了一个额外的 company-dependencies 分层,其中包含所有 groupId 为 com.acme 的库。