打包可執行歸檔

該外掛可以建立包含應用程式所有依賴的可執行檔案(jar 檔案和 war 檔案),然後可以使用 java -jar 執行。

打包可執行 Jar

可執行 jar 可以使用 bootJar 任務構建。當應用 java 外掛時,該任務會自動建立,並且是 BootJar 的一個例項。assemble 任務會自動配置為依賴於 bootJar 任務,因此執行 assemble(或 build)也會執行 bootJar 任務。

打包可執行 War

可執行 war 可以使用 bootWar 任務構建。當應用 war 外掛時,該任務會自動建立,並且是 BootWar 的一個例項。assemble 任務會自動配置為依賴於 bootWar 任務,因此執行 assemble(或 build)也會執行 bootWar 任務。

打包可執行且可部署的 War

War 檔案可以打包成既可以透過 java -jar 執行,又可以部署到外部容器。為此,應將嵌入式 Servlet 容器執行時新增到 providedRuntime 配置中,例如

  • Groovy

  • Kotlin

dependencies {
	implementation('org.springframework.boot:spring-boot-starter-webmvc')
	providedRuntime('org.springframework.boot:spring-boot-starter-tomcat-runtime')
}
dependencies {
	implementation("org.springframework.boot:spring-boot-starter-web")
	providedRuntime("org.springframework.boot:spring-boot-starter-tomcat-runtime")
}

這確保了執行時 jar 被打包到 war 檔案的 WEB-INF/lib-provided 目錄中,這樣它們就不會與外部容器自身的類發生衝突。

providedRuntime 優於 Gradle 的 compileOnly 配置,因為除其他限制外,compileOnly 依賴項不在測試類路徑上,因此任何基於 Web 的整合測試都將失敗。

打包可執行和普通檔案

預設情況下,當配置 bootJarbootWar 任務時,jarwar 任務會配置為使用 plain 作為其檔案分類器的約定。這確保了 bootJarjarbootWarwar 具有不同的輸出位置,允許同時構建可執行檔案和普通檔案。

如果你更喜歡可執行檔案(而不是普通檔案)使用分類器,請按照以下示例為 jarbootJar 任務配置分類器

  • Groovy

  • Kotlin

tasks.named("bootJar") {
	archiveClassifier = 'boot'
}

tasks.named("jar") {
	archiveClassifier = ''
}
tasks.named<BootJar>("bootJar") {
	archiveClassifier.set("boot")
}

tasks.named<Jar>("jar") {
	archiveClassifier.set("")
}

或者,如果你根本不希望構建普通檔案,請停用其任務,如以下 jar 任務示例所示

  • Groovy

  • Kotlin

tasks.named("jar") {
	enabled = false
}
tasks.named<Jar>("jar") {
	enabled = false
}
建立原生映象時,不要停用 jar 任務。詳情請參見 #33238

配置可執行檔案打包

BootJarBootWar 任務分別是 Gradle 的 JarWar 任務的子類。因此,打包 jar 或 war 時可用的所有標準配置選項,在打包可執行 jar 或 war 時也可用。還提供了許多特定於可執行 jar 和 war 的配置選項。

配置主類

預設情況下,可執行檔案的主類將透過在主源集的輸出中查詢具有 public static void main(String[]) 方法的類來自動配置。

主類也可以使用任務的 mainClass 屬性顯式配置

  • Groovy

  • Kotlin

tasks.named("bootJar") {
	mainClass = 'com.example.ExampleApplication'
}
tasks.named<BootJar>("bootJar") {
	mainClass.set("com.example.ExampleApplication")
}

或者,可以使用 Spring Boot DSL 的 mainClass 屬性在專案範圍內配置主類名稱

  • Groovy

  • Kotlin

springBoot {
	mainClass = 'com.example.ExampleApplication'
}
springBoot {
	mainClass.set("com.example.ExampleApplication")
}

如果已應用 application 外掛,則必須配置其 mainClass 屬性,並可用於相同的目的

  • Groovy

  • Kotlin

application {
	mainClass = 'com.example.ExampleApplication'
}
application {
	mainClass.set("com.example.ExampleApplication")
}

最後,可以在任務的清單中配置 Start-Class 屬性

  • Groovy

  • Kotlin

tasks.named("bootJar") {
	manifest {
		attributes 'Start-Class': 'com.example.ExampleApplication'
	}
}
tasks.named<BootJar>("bootJar") {
	manifest {
		attributes("Start-Class" to "com.example.ExampleApplication")
	}
}
如果主類是用 Kotlin 編寫的,則應使用生成的 Java 類的名稱。預設情況下,這是 Kotlin 類的名稱加上 Kt 字尾。例如,ExampleApplication 變為 ExampleApplicationKt。如果使用 @JvmName 定義了另一個名稱,則應使用該名稱。

包含僅限開發環境的依賴項

預設情況下,developmentOnly 配置中宣告的所有依賴項都將從可執行 jar 或 war 中排除。

如果你希望在檔案中包含 developmentOnly 配置中宣告的依賴項,請將其任務的類路徑配置為包含該配置,如以下 bootWar 任務示例所示

  • Groovy

  • Kotlin

tasks.named("bootWar") {
	classpath configurations.developmentOnly
}
tasks.named<BootWar>("bootWar") {
	classpath(configurations["developmentOnly"])
}

配置需要解壓的庫

大多數庫在巢狀在可執行檔案中時可以直接使用,但是某些庫可能會出現問題。例如,JRuby 包含其自己的巢狀 jar 支援,它假設 jruby-complete.jar 始終直接在檔案系統上可用。

為了處理任何有問題的庫,可執行檔案可以配置為在執行時將特定的巢狀 jar 解壓到臨時目錄。可以使用 Ant 風格的模式來識別需要解壓的庫,這些模式與源 jar 檔案的絕對路徑匹配

  • Groovy

  • Kotlin

tasks.named("bootJar") {
	requiresUnpack '**/jruby-complete-*.jar'
}
tasks.named<BootJar>("bootJar") {
	requiresUnpack("**/jruby-complete-*.jar")
}

為了獲得更多控制權,還可以使用閉包。閉包會傳遞一個 FileTreeElement,並且應該返回一個 boolean 值,指示是否需要解壓。

使用 PropertiesLauncher

要使用 PropertiesLauncher 啟動可執行 jar 或 war,請配置任務的清單以設定 Main-Class 屬性

  • Groovy

  • Kotlin

tasks.named("bootWar") {
	manifest {
		attributes 'Main-Class': 'org.springframework.boot.loader.launch.PropertiesLauncher'
	}
}
tasks.named<BootWar>("bootWar") {
	manifest {
		attributes("Main-Class" to "org.springframework.boot.loader.launch.PropertiesLauncher")
	}
}

打包分層 Jar 或 War

預設情況下,bootJar 任務構建的檔案包含應用程式的類和依賴項分別在 BOOT-INF/classesBOOT-INF/lib 中。類似地,bootWar 構建的檔案包含應用程式的類在 WEB-INF/classes 中,依賴項在 WEB-INF/libWEB-INF/lib-provided 中。在需要從 jar 內容構建 Docker 映象的情況下,能夠進一步分離這些目錄以便將它們寫入不同的層是很有用的。

分層 jar 使用與常規 boot 打包 jar 相同的佈局,但包含一個額外的元資料檔案,該檔案描述了每個層。

預設情況下,定義了以下層

  • dependencies 用於所有版本不包含 SNAPSHOT 的非專案依賴。

  • spring-boot-loader 用於 jar 載入器類。

  • snapshot-dependencies 用於所有版本包含 SNAPSHOT 的非專案依賴。

  • application 用於專案依賴、應用程式類和資源。

層的順序很重要,因為它決定了當應用程式的一部分發生變化時,前一層被快取的可能性。預設順序是 dependenciesspring-boot-loadersnapshot-dependenciesapplication。最不可能更改的內容應首先新增,然後是更可能更改的層。

要停用此功能,可以按以下方式操作

  • Groovy

  • Kotlin

tasks.named("bootJar") {
	layered {
		enabled = false
	}
}
tasks.named<BootJar>("bootJar") {
	layered {
		enabled.set(false)
	}
}

建立分層 jar 或 war 時,spring-boot-jarmode-tools jar 將作為依賴項新增到你的檔案中。有了這個 jar 在類路徑上,你可以以一種特殊模式啟動應用程式,該模式允許引導程式碼執行與應用程式完全不同的東西,例如,提取層的程式碼。如果你希望排除此依賴項,可以按以下方式操作

  • Groovy

  • Kotlin

tasks.named("bootJar") {
	includeTools = false
}
tasks.named<BootJar>("bootJar") {
	includeTools.set(false)
}

自定義層配置

根據你的應用程式,你可能需要調整層的建立方式並新增新層。

這可以透過描述 jar 或 war 如何分離成層以及這些層的順序的配置來完成。以下示例展示瞭如何明確定義上述預設順序

  • Groovy

  • Kotlin

tasks.named("bootJar") {
	layered {
		application {
			intoLayer("spring-boot-loader") {
				include "org/springframework/boot/loader/**"
			}
			intoLayer("application")
		}
		dependencies {
			intoLayer("application") {
				includeProjectDependencies()
			}
			intoLayer("snapshot-dependencies") {
				include "*:*:*SNAPSHOT"
			}
			intoLayer("dependencies")
		}
		layerOrder = ["dependencies", "spring-boot-loader", "snapshot-dependencies", "application"]
	}
}
tasks.named<BootJar>("bootJar") {
	layered {
		application {
			intoLayer("spring-boot-loader") {
				include("org/springframework/boot/loader/**")
			}
			intoLayer("application")
		}
		dependencies {
			intoLayer("application") {
				includeProjectDependencies()
			}
			intoLayer("snapshot-dependencies") {
				include("*:*:*SNAPSHOT")
			}
			intoLayer("dependencies")
		}
		layerOrder.set(listOf("dependencies", "spring-boot-loader", "snapshot-dependencies", "application"))
	}
}

layered DSL 由三個部分定義

  • application 閉包定義了應用程式類和資源應該如何分層。

  • dependencies 閉包定義了依賴項應該如何分層。

  • layerOrder 方法定義了層的寫入順序。

巢狀的 intoLayer 閉包用於 applicationdependencies 部分中,以宣告層的內容。這些閉包按照它們定義的順序從上到下進行評估。任何未被早期 intoLayer 閉包宣告的內容都可供後續閉包考慮。

intoLayer 閉包使用巢狀的 includeexclude 呼叫來宣告內容。application 閉包使用 Ant 風格的路徑匹配作為 include/exclude 引數。dependencies 部分使用 group:artifact[:version] 模式。它還提供了 includeProjectDependencies()excludeProjectDependencies() 方法,可用於包含或排除專案依賴項。

如果沒有進行 include 呼叫,則所有內容(未被早期閉包宣告的)都會被考慮。

如果沒有進行 exclude 呼叫,則不應用任何排除。

看上面的 dependencies 閉包示例,我們可以看到第一個 intoLayer 將為 application 層宣告所有專案依賴項。下一個 intoLayer 將為 snapshot-dependencies 層宣告所有 SNAPSHOT 依賴項。第三個也是最後一個 intoLayer 將為 dependencies 層宣告剩餘的任何內容(在此例中,任何不是專案依賴項或 SNAPSHOT 的依賴項)。

application 閉包有類似的規則。首先為 spring-boot-loader 層宣告 org/springframework/boot/loader/** 內容。然後為 application 層宣告任何剩餘的類和資源。

新增 intoLayer 閉包的順序通常與寫入層的順序不同。因此,layerOrder 方法必須始終被呼叫,並且必須覆蓋 intoLayer 呼叫引用的所有層。
© . This site is unofficial and not affiliated with VMware.