打包可執行檔案

該外掛可以建立包含應用程式所有依賴項的可執行檔案(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 的庫。