打包可执行存档
该插件可以创建包含应用程序所有依赖项的可执行存档(jar 文件和 war 文件),然后可以使用 java -jar
运行。
打包可执行 Jar 文件
可以使用 bootJar
任务构建可执行 jar 文件。当应用 java
插件时,该任务会自动创建,并且是 BootJar
的实例。assemble
任务会自动配置为依赖于 bootJar
任务,因此运行 assemble
(或 build
)也会运行 bootJar
任务。
打包可执行 War 文件
可以使用 bootWar
任务构建可执行 war 文件。当应用 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 解压缩到临时目录。可以使用 Ant 风格的模式来识别需要解压缩的库,这些模式与源 jar 文件的绝对路径匹配。
-
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 使用与常规引导打包 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
闭包使用 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 调用引用的所有层。
|