|
此版本仍在开发中,尚未被视为稳定版本。如需最新稳定版本,请使用 Spring Boot 4.0.4! |
打包可执行归档文件
该插件可以创建可执行的归档文件(jar 文件和 war 文件),其中包含应用程序的所有依赖项,然后可以使用 java -jar 运行。
打包可执行 JAR 文件
可以使用 bootJar 任务构建可执行 jar 包。
当应用 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-web')
providedRuntime('org.springframework.boot:spring-boot-starter-tomcat')
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
providedRuntime("org.springframework.boot:spring-boot-starter-tomcat")
}
这确保它们被打包在 WAR 文件的 WEB-INF/lib-provided 目录中,从而不会与外部容器自身的类发生冲突。
推荐使用 providedRuntime 而非 Gradle 的 compileOnly 配置,因为除了其他限制外,compileOnly 依赖项不在测试类路径上,因此任何基于 Web 的集成测试都会失败。 |
打包可执行和普通归档文件
默认情况下,当配置了 bootJar 或 bootWar 任务时,jar 或 war 任务被配置为使用 plain 作为其归档分类器的约定。
这确保了 bootJar 和 jar 或 bootWar 和 war 具有不同的输出位置,从而允许同时构建可执行归档和普通归档。
如果您希望可执行归档(而非普通归档)使用分类器,请按照以下 jar 和 bootJar 任务的示例配置分类器:
-
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。 |
配置可执行归档打包
BootJar 和 BootWar 任务分别是 Gradle 的 Jar 和 War 任务的子类。
因此,在打包 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 文件配置为解压到临时目录中。 可以使用匹配源 JAR 文件绝对路径的 Ant 风格模式来识别需要解压的库:
-
Groovy
-
Kotlin
tasks.named("bootJar") {
requiresUnpack '**/jruby-complete-*.jar'
}
tasks.named<BootJar>("bootJar") {
requiresUnpack("**/jruby-complete-*.jar")
}
如需更多控制,也可以使用闭包。
该闭包接收一个 FileTreeElement,并应返回一个 boolean 以指示是否需要解包。
使归档文件完全可执行
Spring Boot 提供对完全可执行归档文件的支持。 通过在归档文件前添加一个能够启动应用程序的 shell 脚本,使其成为完全可执行文件。 在类 Unix 平台上,此启动脚本允许归档文件像其他任何可执行文件一样直接运行,或作为服务进行安装。
目前,某些工具不支持此格式,因此您可能无法始终使用此技术。
例如,jar -xf 可能在提取已制成完全可执行的 jar 或 war 文件时静默失败。
建议您仅在打算直接执行它,而不是使用 java -jar 运行它或将其部署到 Servlet 容器时才启用此选项。 |
要使用此功能,必须启用启动脚本的包含:
-
Groovy
-
Kotlin
tasks.named("bootJar") {
launchScript()
}
tasks.named<BootJar>("bootJar") {
launchScript()
}
这会将 Spring Boot 的默认启动脚本添加到归档文件中。
默认启动脚本包含多个具有合理默认值的属性。
可以使用 properties 属性自定义这些值:
-
Groovy
-
Kotlin
tasks.named("bootJar") {
launchScript {
properties 'logFilename': 'example-app.log'
}
}
tasks.named<BootJar>("bootJar") {
launchScript {
properties(mapOf("logFilename" to "example-app.log"))
}
}
如果默认启动脚本无法满足您的需求,可以使用 script 属性来提供自定义的启动脚本:
-
Groovy
-
Kotlin
tasks.named("bootJar") {
launchScript {
script = file('src/custom.script')
}
}
tasks.named<BootJar>("bootJar") {
launchScript {
script = file("src/custom.script")
}
}
使用 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/classes 和 BOOT-INF/lib 中的应用程序类和依赖项。
类似地,bootWar 会构建一个归档文件,其中包含位于 WEB-INF/classes 中的应用程序类,以及位于 WEB-INF/lib 和 WEB-INF/lib-provided 中的依赖项。
在需要从 jar 包内容构建 Docker 镜像的情况下,能够进一步分离这些目录以便将它们写入不同的层是非常有用的。
分层 JAR 使用与常规 Spring Boot 打包 JAR 相同的布局,但包含一个额外的元数据文件,用于描述每个层。
默认情况下,定义了以下层:
-
dependencies用于任何不包含SNAPSHOT的非项目依赖项的版本。 -
spring-boot-loader用于 jar 加载器类。 -
snapshot-dependencies用于任何非项目依赖项,其版本包含SNAPSHOT。 -
application用于项目依赖项、应用程序类和资源。
层的顺序很重要,因为它决定了当应用程序的部分内容发生变化时,之前的层被缓存的可能性。
默认顺序是 dependencies、spring-boot-loader、snapshot-dependencies、application。
最不可能变化的内容应首先添加,然后是更可能变化的层。
要禁用此功能,您可以按以下方式进行:
-
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 闭包在 application 和 dependencies 部分中用于声明层的内容。
这些闭包按照定义的顺序,从上到下进行求值。
任何未被前面的 intoLayer 闭包声明的内容仍然可供后续的闭包考虑。
intoLayer 闭包使用嵌套的 include 和 exclude 调用来声明内容。
application 闭包对 include/exclude 参数使用 Ant 风格的路径匹配。
dependencies 部分使用 group:artifact[:version] 模式。
它还提供了 includeProjectDependencies() 和 excludeProjectDependencies() 方法,可用于包含或排除项目依赖项。
如果未进行 include 调用,则会考虑所有内容(未被早期闭包声明的内容)。
如果未进行 exclude 调用,则不会应用任何排除项。
查看上面示例中的 dependencies 闭包,我们可以看到第一个 intoLayer 将声明 application 层的所有项目依赖项。
下一个 intoLayer 将声明 snapshot-dependencies 层的所有 SNAPSHOT 依赖项。
第三个也是最后一个 intoLayer 将声明剩余的任何内容(在本例中,任何非项目依赖项或非 SNAPSHOT 的依赖项)用于 dependencies 层。
application 闭包具有类似的规则。
首先为 spring-boot-loader 层声明 org/springframework/boot/loader/** 内容。
然后为 application 层声明任何剩余的类和资源。
添加 intoLayer 闭包的顺序通常与编写层的顺序不同。
因此,必须始终调用 layerOrder 方法,并且必须涵盖由 intoLayer 调用引用的所有层。 |