2017-03-15 04:51:23 +08:00
[[packaging-executable]]
== Packaging executable archives
2019-09-09 17:59:49 +08:00
The plugin can create executable archives (jar files and war files) that contain all of an application's dependencies and can then be run with `java -jar`.
2017-03-15 04:51:23 +08:00
[[packaging-executable-jars]]
=== Packaging executable jars
2019-09-09 17:59:49 +08:00
Executable jars can be built using the `bootJar` task.
The task is automatically created when the `java` plugin is applied and is an instance of {boot-jar-javadoc}[`BootJar`].
The `assemble` task is automatically configured to depend upon the `bootJar` task so running `assemble` (or `build`) will also run the `bootJar` task.
2017-03-15 04:51:23 +08:00
[[packaging-executable-wars]]
=== Packaging executable wars
2019-09-09 17:59:49 +08:00
Executable wars can be built using the `bootWar` task.
The task is automatically created when the `war` plugin is applied and is an instance of {boot-war-javadoc}[`BootWar`].
The `assemble` task is automatically configured to depend upon the `bootWar` task so running `assemble` (or `build`) will also run the `bootWar` task.
2017-03-15 04:51:23 +08:00
[[packaging-executable-wars-deployable]]
==== Packaging executable and deployable wars
2019-09-09 17:59:49 +08:00
A war file can be packaged such that it can be executed using `java -jar` and deployed to an external container.
To do so, the embedded servlet container dependencies should be added to the `providedRuntime` configuration, for example:
2017-03-15 04:51:23 +08:00
2018-09-23 04:39:36 +08:00
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy
2017-03-15 04:51:23 +08:00
----
include::../gradle/packaging/war-container-dependency.gradle[tags=dependencies]
----
2018-09-23 04:39:36 +08:00
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::../gradle/packaging/war-container-dependency.gradle.kts[tags=dependencies]
----
2019-09-09 17:59:49 +08:00
This ensures that they are package in the war file's `WEB-INF/lib-provided` directory from where they will not conflict with the external container's own classes.
2017-03-15 04:51:23 +08:00
2019-09-09 17:59:49 +08:00
NOTE: `providedRuntime` is preferred to Gradle's `compileOnly` configuration as, among other limitations, `compileOnly` dependencies are not on the test classpath so any web-based integration tests will fail.
2017-03-15 04:51:23 +08:00
2017-04-28 23:48:48 +08:00
[[packaging-executable-and-normal]]
=== Packaging executable and normal archives
2019-09-09 17:59:49 +08:00
By default, when the `bootJar` or `bootWar` tasks are configured, the `jar` or `war` tasks are disabled.
A project can be configured to build both an executable archive and a normal archive at the same time by enabling the `jar` or `war` task:
2017-04-28 23:48:48 +08:00
2018-09-23 04:39:36 +08:00
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy
2017-04-28 23:48:48 +08:00
----
include::../gradle/packaging/boot-jar-and-jar.gradle[tags=enable-jar]
----
2018-09-23 04:39:36 +08:00
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::../gradle/packaging/boot-jar-and-jar.gradle.kts[tags=enable-jar]
----
2019-09-09 17:59:49 +08:00
To avoid the executable archive and the normal archive from being written to the same location, one or the other should be configured to use a different location.
One way to do so is by configuring a classifier:
2017-04-28 23:48:48 +08:00
2018-09-23 04:39:36 +08:00
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy
2017-04-28 23:48:48 +08:00
----
include::../gradle/packaging/boot-jar-and-jar.gradle[tags=classifier]
----
2018-09-23 04:39:36 +08:00
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::../gradle/packaging/boot-jar-and-jar.gradle.kts[tags=classifier]
----
2017-03-15 04:51:23 +08:00
[[packaging-executable-configuring]]
=== Configuring executable archive packaging
2019-09-09 17:59:49 +08:00
The {boot-jar-javadoc}[`BootJar`] and {boot-war-javadoc}[`BootWar`] tasks are subclasses of Gradle's `Jar` and `War` tasks respectively.
As a result, all of the standard configuration options that are available when packaging a jar or war are also available when packaging an executable jar or war.
A number of configuration options that are specific to executable jars and wars are also provided.
2017-03-15 04:51:23 +08:00
[[packaging-executable-configuring-main-class]]
==== Configuring the main class
2019-09-09 17:59:49 +08:00
By default, the executable archive's main class will be configured automatically by looking for a class with a `public static void main(String[])` method in directories on the task's classpath.
2017-03-15 04:51:23 +08:00
2019-09-09 17:59:49 +08:00
The main class can also be configured explicitly using the task's `mainClassName` property:
2017-03-15 04:51:23 +08:00
2018-09-23 04:39:36 +08:00
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy
2017-03-15 04:51:23 +08:00
----
include::../gradle/packaging/boot-jar-main-class.gradle[tags=main-class]
----
2018-09-23 04:39:36 +08:00
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::../gradle/packaging/boot-jar-main-class.gradle.kts[tags=main-class]
----
2019-09-09 17:59:49 +08:00
Alternatively, the main class name can be configured project-wide using the `mainClassName` property of the Spring Boot DSL:
2017-10-19 20:55:13 +08:00
2018-09-23 04:39:36 +08:00
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy
2017-10-19 20:55:13 +08:00
----
include::../gradle/packaging/spring-boot-dsl-main-class.gradle[tags=main-class]
----
2018-09-23 04:39:36 +08:00
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::../gradle/packaging/spring-boot-dsl-main-class.gradle.kts[tags=main-class]
----
2019-09-09 17:59:49 +08:00
If the {application-plugin}[`application` plugin] has been applied its `mainClassName` project property must be configured and can be used for the same purpose:
2017-03-15 04:51:23 +08:00
2018-09-23 04:39:36 +08:00
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy
2017-03-15 04:51:23 +08:00
----
include::../gradle/packaging/application-plugin-main-class.gradle[tags=main-class]
----
2018-09-23 04:39:36 +08:00
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::../gradle/packaging/application-plugin-main-class.gradle.kts[tags=main-class]
----
2017-03-15 04:51:23 +08:00
Lastly, the `Start-Class` attribute can be configured on the task's manifest:
2018-09-23 04:39:36 +08:00
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy
2017-03-15 04:51:23 +08:00
----
include::../gradle/packaging/boot-jar-manifest-main-class.gradle[tags=main-class]
----
2018-09-23 04:39:36 +08:00
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::../gradle/packaging/boot-jar-manifest-main-class.gradle.kts[tags=main-class]
----
2017-03-15 04:51:23 +08:00
2020-01-31 09:02:47 +08:00
2017-03-15 04:51:23 +08:00
[[packaging-executable-configuring-excluding-devtools]]
==== Excluding Devtools
2019-09-09 17:59:49 +08:00
By default, Spring Boot's Devtools module, `org.springframework.boot:spring-boot-devtools`, will be excluded from an executable jar or war.
If you want to include Devtools in your archive set the `excludeDevtools` property to `false`:
2017-03-15 04:51:23 +08:00
2018-09-23 04:39:36 +08:00
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy
2017-03-15 04:51:23 +08:00
----
include::../gradle/packaging/boot-war-include-devtools.gradle[tags=include-devtools]
----
2018-09-23 04:39:36 +08:00
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::../gradle/packaging/boot-war-include-devtools.gradle.kts[tags=include-devtools]
----
2017-03-15 04:51:23 +08:00
2020-01-31 09:02:47 +08:00
2017-03-15 04:51:23 +08:00
[[packaging-executable-configuring-unpacking]]
==== Configuring libraries that require unpacking
2019-09-09 17:59:49 +08:00
Most libraries can be used directly when nested in an executable archive, however certain libraries can have problems.
For example, JRuby includes its own nested jar support which assumes that `jruby-complete.jar` is always directly available on the file system.
2017-03-15 04:51:23 +08:00
2019-09-09 17:59:49 +08:00
To deal with any problematic libraries, an executable archive can be configured to unpack specific nested jars to a temporary folder when the executable archive is run.
Libraries can be identified as requiring unpacking using Ant-style patterns that match against the absolute path of the source jar file:
2017-03-15 04:51:23 +08:00
2018-09-23 04:39:36 +08:00
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy
2017-03-15 04:51:23 +08:00
----
include::../gradle/packaging/boot-jar-requires-unpack.gradle[tags=requires-unpack]
----
2018-09-23 04:39:36 +08:00
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::../gradle/packaging/boot-jar-requires-unpack.gradle.kts[tags=requires-unpack]
----
2019-09-09 17:59:49 +08:00
For more control a closure can also be used.
The closure is passed a `FileTreeElement` and should return a `boolean` indicating whether or not unpacking is required.
2017-03-15 04:51:23 +08:00
[[packaging-executable-configuring-launch-script]]
==== Making an archive fully executable
2019-09-09 17:59:49 +08:00
Spring Boot provides support for fully executable archives.
An archive is made fully executable by prepending a shell script that knows how to launch the application.
On Unix-like platforms, this launch script allows the archive to be run directly like any other executable or to be installed as a service.
2017-03-15 04:51:23 +08:00
To use this feature, the inclusion of the launch script must be enabled:
2018-09-23 04:39:36 +08:00
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy
2017-03-15 04:51:23 +08:00
----
include::../gradle/packaging/boot-jar-include-launch-script.gradle[tags=include-launch-script]
----
2018-09-23 04:39:36 +08:00
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::../gradle/packaging/boot-jar-include-launch-script.gradle.kts[tags=include-launch-script]
----
2019-09-09 17:59:49 +08:00
This will add Spring Boot's default launch script to the archive.
The default launch script includes several properties with sensible default values.
The values can be customized using the `properties` property:
2017-03-15 04:51:23 +08:00
2018-09-23 04:39:36 +08:00
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy
2017-03-15 04:51:23 +08:00
----
include::../gradle/packaging/boot-jar-launch-script-properties.gradle[tags=launch-script-properties]
----
2018-09-23 04:39:36 +08:00
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::../gradle/packaging/boot-jar-launch-script-properties.gradle.kts[tags=launch-script-properties]
----
2019-09-09 17:59:49 +08:00
If the default launch script does not meet your needs, the `script` property can be used to provide a custom launch script:
2017-03-15 04:51:23 +08:00
2018-09-23 04:39:36 +08:00
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy
2017-03-15 04:51:23 +08:00
----
include::../gradle/packaging/boot-jar-custom-launch-script.gradle[tags=custom-launch-script]
----
2018-09-23 04:39:36 +08:00
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::../gradle/packaging/boot-jar-custom-launch-script.gradle.kts[tags=custom-launch-script]
----
2017-03-15 04:51:23 +08:00
2020-01-31 09:02:47 +08:00
2017-03-15 04:51:23 +08:00
[[packaging-executable-configuring-properties-launcher]]
==== Using the `PropertiesLauncher`
2019-09-09 17:59:49 +08:00
To use the `PropertiesLauncher` to launch an executable jar or war, configure the task's manifest to set the `Main-Class` attribute:
2017-03-15 04:51:23 +08:00
2018-09-23 04:39:36 +08:00
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy
2017-03-15 04:51:23 +08:00
----
include::../gradle/packaging/boot-war-properties-launcher.gradle[tags=properties-launcher]
2017-04-28 23:48:48 +08:00
----
2018-09-23 04:39:36 +08:00
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::../gradle/packaging/boot-war-properties-launcher.gradle.kts[tags=properties-launcher]
----
2020-01-19 02:57:12 +08:00
2020-01-31 09:02:47 +08:00
2020-01-19 02:57:12 +08:00
[[packaging-layered-jars]]
==== Packaging layered jars
2020-03-11 07:09:44 +08:00
By default, the `bootJar` task builds an archive that contains the application's classes and dependencies in `BOOT-INF/classes` and `BOOT-INF/lib` respectively.
2020-01-19 02:57:12 +08:00
For cases where a docker image needs to be built from the contents of the jar, the jar format can be enhanced to support layer folders.
To use this feature, the layering feature must be enabled:
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy
----
include::../gradle/packaging/boot-jar-layered.gradle[tags=layered]
----
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::../gradle/packaging/boot-jar-layered.gradle.kts[tags=layered]
----
2020-03-11 07:09:44 +08:00
By default, the following layers are created:
2020-01-19 02:57:12 +08:00
2020-03-11 07:09:44 +08:00
* `dependencies` for any dependency whose version does not contain `SNAPSHOT`.
* `snapshot-dependencies` for any dependency whose version contains `SNAPSHOT`.
2020-03-24 03:59:42 +08:00
* `application` for application classes and resources.
2020-03-11 07:09:44 +08:00
The layers order is important as it determines how likely previous layers can be cached when part of the application changes.
2020-03-24 03:59:42 +08:00
The default order is `dependencies`, `snapshot-dependencies`, and `application`.
2020-03-11 07:09:44 +08:00
Content that is least likely to change should be added first, followed by layers that are more likely to change.
2020-01-22 22:54:32 +08:00
2020-02-08 08:02:35 +08:00
When you create a layered jar, the `spring-boot-layertools` jar will be added as a dependency to your jar.
With this jar on the classpath, you can launch your application in a special mode which allows the bootstrap code to run something entirely different from your application, for example, something that extracts the layers.
If you wish to exclude this dependency, you can do so in the following manner:
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy
----
include::../gradle/packaging/boot-jar-layered-exclude-tools.gradle[tags=layered]
----
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::../gradle/packaging/boot-jar-layered-exclude-tools.gradle.kts[tags=layered]
2020-03-11 07:09:44 +08:00
----
2020-03-24 11:03:44 +08:00
2020-03-11 07:09:44 +08:00
[[packaging-layers-configuration]]
===== Custom Layers configuration
Depending on your application, you may want to tune how layers are created and add new ones.
This can be done using configuration that lists the layers and their order as well as the strategies to apply to libraries and classes.
The following example shows what the implicit layer configuration described above does:
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy
----
include::../gradle/packaging/boot-jar-layered-custom.gradle[tags=layered]
----
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::../gradle/packaging/boot-jar-layered-custom.gradle.kts[tags=layered]
----
Each `layerContent` closure defines a strategy to include or exclude an entry of the jar in a layer.
When an entry matches a strategy, it is included in the layer and further strategies are ignored.
2020-03-24 03:59:42 +08:00
This is illustrated by the `dependencies` layer that has a "catch-all" include filter used to add any libraries that were not processed by previous strategies.
2020-03-11 07:09:44 +08:00
The content of a `libraries` layer can be customized using filters to `include` or `exclude` based on the dependency coordinates.
The format is `groupId:artifactId[:version]`.
In the example above, any artifact whose version ends with `SNAPSHOT` is going to be included in the `snapshot-dependencies` layer.
2020-03-24 04:01:16 +08:00
The content of a `application` layer can be customized using filters to `includ` or `exclude` based on location of the entry using Ant-style pattern matching.