Update Maven and Gradle layer customization docs

Update the Maven and Gradle documentation following the refined
layer customization changes.

See gh-20526
pull/20830/head
Phillip Webb 5 years ago
parent 0e1394ef30
commit 12bc890e75

@ -8031,7 +8031,7 @@ For Gradle, refer to the {spring-boot-gradle-plugin-docs}/#packaging-layered-jar
=== Writing the Dockerfile === Writing the Dockerfile
When you create a layered jar, the `spring-boot-jarmode-layertools` jar will be added as a dependency to your jar. When you create a jar containing the layers index file, the `spring-boot-jarmode-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. 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.
Heres how you can launch your jar with a `layertools` jar mode: Heres how you can launch your jar with a `layertools` jar mode:

@ -265,7 +265,9 @@ include::../gradle/packaging/boot-war-properties-launcher.gradle.kts[tags=proper
[[packaging-layered-jars]] [[packaging-layered-jars]]
==== Packaging layered jars ==== Packaging layered jars
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. 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.
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. For cases where a docker image needs to be built from the contents of the jar, it's useful to be able to separate these folders futher so that they can be written into distinct layers.
Layered jars use the same layout as regular boot packaged jars, but include an additional meta-data file that describes each layer.
To use this feature, the layering feature must be enabled: To use this feature, the layering feature must be enabled:
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"] [source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
@ -280,14 +282,15 @@ include::../gradle/packaging/boot-jar-layered.gradle[tags=layered]
include::../gradle/packaging/boot-jar-layered.gradle.kts[tags=layered] include::../gradle/packaging/boot-jar-layered.gradle.kts[tags=layered]
---- ----
By default, the following layers are created: By default, the following layers are defined:
* `dependencies` for any dependency whose version does not contain `SNAPSHOT`. * `dependencies` for any dependency whose version does not contain `SNAPSHOT`.
* `spring-boot-loader` for the jar loader classes.
* `snapshot-dependencies` for any dependency whose version contains `SNAPSHOT`. * `snapshot-dependencies` for any dependency whose version contains `SNAPSHOT`.
* `application` for application classes and resources. * `application` for application classes and resources.
The layers order is important as it determines how likely previous layers can be cached when part of the application changes. The layers order is important as it determines how likely previous layers can be cached when part of the application changes.
The default order is `dependencies`, `snapshot-dependencies`, and `application`. The default order is `dependencies`, `spring-boot-loader`, `snapshot-dependencies`, `application`.
Content that is least likely to change should be added first, followed by layers that are more likely to change. Content that is least likely to change should be added first, followed by layers that are more likely to change.
When you create a layered jar, the `spring-boot-jarmode-layertools` jar will be added as a dependency to your jar. When you create a layered jar, the `spring-boot-jarmode-layertools` jar will be added as a dependency to your jar.
@ -311,9 +314,9 @@ include::../gradle/packaging/boot-jar-layered-exclude-tools.gradle.kts[tags=laye
[[packaging-layers-configuration]] [[packaging-layers-configuration]]
===== Custom Layers configuration ===== Custom Layers configuration
Depending on your application, you may want to tune how layers are created and add new ones. 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: This can be done using configuration that describes how the jar can be separated into layers, and the order of those layers.
The following example shows how the default ordering described above can be defined explicity:
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"] [source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy .Groovy
@ -327,12 +330,30 @@ include::../gradle/packaging/boot-jar-layered-custom.gradle[tags=layered]
include::../gradle/packaging/boot-jar-layered-custom.gradle.kts[tags=layered] 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. The `layered` DSL is defined using three parts:
When an entry matches a strategy, it is included in the layer and further strategies are ignored.
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. * The `application` closure defines how the application classes and resources should be layered.
* The `dependencies` closure defines how dependencies should be layered.
* The `layerOrder` method defines the order that the layers should be written.
Nested `intoLayer` closures are used within `application` and `dependencies` sections to claim content for a layer.
These closures are evaluated in the order that they are defined, from top to bottom.
Any content not claimed by an earlier `intoLayer` closure remains availble for subsequent ones to consider.
The `intoLayer` closurer claims content using nested `include` and `exclude` calls.
The `applicaton` closure uses Ant-style patch matching for include/exclude parameters.
The `dependencies` section uses `group:artifact[:version]` patterns.
If no `include` call is made, then all content (not claimed by an earlier closure) is considered.
If no `exclude` call is made, then no exclusions are applied.
Looking at the `dependencies` closure in the example above, we can see tha the first `intoLayer` will claim all SNAPSHOT dependencies for the `snapshot-dependencies` layer.
The subsequent `intoLayer` will claim anything left (in this case, any dependency that is not a SNAPSHOT) for the `dependencies` layer.
The content of a `libraries` layer can be customized using filters to `include` or `exclude` based on the dependency coordinates. The `application` closure has similar rules.
The format is `groupId:artifactId[:version]`. First claiming `org/springframework/boot/loader/**` content for the `spring-boot-loader` layer.
In the example above, any artifact whose version ends with `SNAPSHOT` is going to be included in the `snapshot-dependencies` layer. Then claiming any remaining classes and resources for the `application` layer.
The content of an `application` layer can be customized using filters to `include` or `exclude` based on location of the entry using Ant-style pattern matching. NOTE: The order that `intoLayer` closures are added is often different from the order that the layers are written.
For this reason the `layerOrder` method must always be called and _must_ cover all layers referenced by the `intoLayer` calls.

@ -11,6 +11,9 @@ bootJar {
bootJar { bootJar {
layered { layered {
application { application {
intoLayer("spring-boot-loader") {
include "org/springframework/boot/loader/**"
}
intoLayer("application") intoLayer("application")
} }
dependencies { dependencies {
@ -19,7 +22,7 @@ bootJar {
} }
intoLayer("dependencies") intoLayer("dependencies")
} }
layerOrder "dependencies", "snapshot-dependencies", "application" layerOrder "dependencies", "spring-boot-loader", "snapshot-dependencies", "application"
} }
} }
// end::layered[] // end::layered[]

@ -9,6 +9,9 @@ plugins {
tasks.getByName<BootJar>("bootJar") { tasks.getByName<BootJar>("bootJar") {
layered { layered {
application { application {
intoLayer("spring-boot-loader") {
include("org/springframework/boot/loader/**")
}
intoLayer("application") intoLayer("application")
} }
dependencies { dependencies {
@ -17,7 +20,7 @@ tasks.getByName<BootJar>("bootJar") {
} }
intoLayer("dependencies") { intoLayer("dependencies") {
} }
layersOrder("dependencies", "snapshot-dependencies", "application") layersOrder("dependencies", "spring-boot-loader", "snapshot-dependencies", "application")
} }
} }
// end::layered[] // end::layered[]

@ -71,11 +71,14 @@ The `layout` property defaults to a guess based on the archive type (`jar` or `w
* `ZIP` (alias to `DIR`): similar to the `JAR` layout using `PropertiesLauncher`. * `ZIP` (alias to `DIR`): similar to the `JAR` layout using `PropertiesLauncher`.
* `NONE`: Bundle all dependencies and project resources. Does not bundle a bootstrap loader. * `NONE`: Bundle all dependencies and project resources. Does not bundle a bootstrap loader.
[[repackage-layers]] [[repackage-layers]]
=== Layered jar === Layered jars
A repackaged jar contains the application's classes and dependencies in `BOOT-INF/classes` and `BOOT-INF/lib` respectively.
For cases where a docker image needs to be built from the contents of the jar, it's useful to be able to separate these folders futher so that they can be written into distinct layers.
By default, a repackaged jar contains the application's classes and dependencies in `BOOT-INF/classes` and `BOOT-INF/lib` respectively. Layered jars use the same layout as regular repackaged jars, but include an additional meta-data file that describes each layer.
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: To use this feature, the layering feature must be enabled:
[source,xml,indent=0,subs="verbatim,attributes"] [source,xml,indent=0,subs="verbatim,attributes"]
@ -98,14 +101,15 @@ To use this feature, the layering feature must be enabled:
</project> </project>
---- ----
By default, the following layers are created: By default, the following layers are defined:
* `dependencies` for any dependency whose version does not contain `SNAPSHOT`. * `dependencies` for any dependency whose version does not contain `SNAPSHOT`.
* `spring-boot-loader` for the jar loader classes.
* `snapshot-dependencies` for any dependency whose version contains `SNAPSHOT`. * `snapshot-dependencies` for any dependency whose version contains `SNAPSHOT`.
* `application` for application classes and resources. * `application` for application classes and resources.
The layers order is important as it determines how likely previous layers can be cached when part of the application changes. The layers order is important as it determines how likely previous layers can be cached when part of the application changes.
The default order is `dependencies`, `snapshot-dependencies`, and `application`. The default order is `dependencies`, `spring-boot-loader`, `snapshot-dependencies`, `application`.
Content that is least likely to change should be added first, followed by layers that are more likely to change. Content that is least likely to change should be added first, followed by layers that are more likely to change.
@ -113,7 +117,7 @@ Content that is least likely to change should be added first, followed by layers
[[repackage-layers-configuration]] [[repackage-layers-configuration]]
==== Custom Layers configuration ==== Custom Layers configuration
Depending on your application, you may want to tune how layers are created and add new ones. Depending on your application, you may want to tune how layers are created and add new ones.
This can be done using a separate configuration file that should be registered as shown in the following example: This can be done using a separate configuration file that should be registered as shown below:
[source,xml,indent=0,subs="verbatim,attributes"] [source,xml,indent=0,subs="verbatim,attributes"]
---- ----
@ -136,53 +140,64 @@ This can be done using a separate configuration file that should be registered a
</project> </project>
---- ----
The configuration file lists the layers and their order as well as the strategies to apply to libraries and classes. The configuration file describes how the jar can be separated into layers, and the order of those layers.
The following example shows what the implicit layer configuration described above does: The following example shows how the default ordering described above can be defined explicity:
[source,xml,indent=0,subs="verbatim,attributes"] [source,xml,indent=0,subs="verbatim,attributes"]
---- ----
<layers-configuration xmlns="http://www.springframework.org/schema/boot/layers" <layers xmlns="http://www.springframework.org/schema/boot/layers"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/boot/layers xsi:schemaLocation="http://www.springframework.org/schema/boot/layers
https://www.springframework.org/schema/boot/layers/layers-configuration-{spring-boot-xsd-version}.xsd"> https://www.springframework.org/schema/boot/layers/layers-{spring-boot-xsd-version}.xsd">
<layers> <application>
<layer>dependencies</layer> <into layer="spring-boot-loader">
<layer>snapshot-dependencies</layer> <include>org/springframework/boot/loader/**</include>
<layer>application</layer> </into>
</layers> <into layer="application" />
<libraries> </application>
<layer-content layer="snapshot-dependencies"> <dependencies>
<coordinates> <into layer="snapshot-dependencies">
<include>*:*:*SNAPSHOT</include> <include>*:*:*SNAPSHOT</include>
</coordinates> </into>
</layer-content> <into layer="dependencies" />
<layer-content layer="dependencies"> </dependencies>
<coordinates> <layerOrder>
<include>*:*</include> <layer>dependencies</layer>
</coordinates> <layer>spring-boot-loader</layer>
</layer-content> <layer>snapshot-dependencies</layer>
</libraries> <layer>application</layer>
<application> </layerOrder>
<layer-content layer="application"> </layers>
<locations>
<include>**</include>
</locations>
</layer-content>
</application>
</layers-configuration>
---- ----
Each `layer-content` element 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.
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.
The content of a `libraries` layer can be customized using filters to `include` or `exclude` based on the dependency coordinates. The `layers` XML format is defined in three sections:
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. * The `<application>` block defines how the application classes and resources should be layered.
* The `<dependencies>` block defines how dependencies should be layered.
* The `<layerOrder>` block defines the order that the layers should be written.
Nested `<into>` blocks are used within `<application>` and `<dependencies>` sections to claim content for a layer.
The blocks are evaluated in the order that they are defined, from top to bottom.
Any content not claimed by an earlier block remains availble for subsequent blocks to consider.
The `<into>` block claims content using nested `<include>` and `<exclude>` elements.
The `<applicaton>` section uses Ant-style patch matching for include/exclude expressions.
The `<dependencies>` section uses `group:artifact[:version]` patterns.
The content of an `application` layer can be customized using filters to `include` or `exclude` based on location of the entry using Ant-style pattern matching. If no `<include>` is defined, then all content (not claimed by an earlier block) is considered.
If no `<exclude>` is defined, then no exclusions are applied.
Looking at the `<dependencies>` example above, we can see tha the first `<into>` will claim all SNAPSHOT dependencies for the `snapshot-dependencies` layer.
The subsequent `<into>` will claim anything left (in this case, any dependency that is not a SNAPSHOT) for the `dependencies` layer.
The `<application>` block has similar rules.
First claiming `org/springframework/boot/loader/**` content for the `spring-boot-loader` layer.
Then claiming any remaining classes and resources for the `application` layer.
NOTE: The order that `<into>` blocks are defined is often different from the order that the layers are written.
For this reason the `<layerOrder>` element must always be included and _must_ cover all layers referenced by the `<into>` blocks.
include::goals/repackage.adoc[leveloffset=+1] include::goals/repackage.adoc[leveloffset=+1]
@ -515,7 +530,6 @@ This example excludes any artifact belonging to the `com.foo` group:
[[repackage-layered-jars-tools]] [[repackage-layered-jars-tools]]
==== Layered jar tools ==== Layered jar tools
When you create a layered jar, the `spring-boot-jarmode-layertools` jar will be added as a dependency to your jar. When you create a layered jar, the `spring-boot-jarmode-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. 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: If you wish to exclude this dependency, you can do so in the following manner:
@ -545,44 +559,39 @@ If you wish to exclude this dependency, you can do so in the following manner:
[[repackage-layered-jars-additional-layers]] [[repackage-layered-jars-additional-layers]]
==== Custom layers configuration ==== Custom layers configuration
The default setup splits dependencies into snaphost and non-snapshot, however, you may have more complex rules.
While the default setup creates two layers for libraries, you may want to isolate the dependencies of your project in a dedicated layer. For example, you may want to isolate company-specific dependencies of your project in a dedicated layer.
This allows to reuse the cache for external dependencies when an internal dependency has changed, as shown by the following example: The following `layers.xml` configuration shown one such setup:
[source,xml,indent=0,subs="verbatim,attributes"] [source,xml,indent=0,subs="verbatim,attributes"]
---- ----
<layers-configuration xmlns="http://www.springframework.org/schema/boot/layers" <layers xmlns="http://www.springframework.org/schema/boot/layers"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/boot/layers xsi:schemaLocation="http://www.springframework.org/schema/boot/layers
https://www.springframework.org/schema/boot/layers/layers-configuration-{spring-boot-xsd-version}.xsd"> https://www.springframework.org/schema/boot/layers/layers-{spring-boot-xsd-version}.xsd">
<layers>
<layer>application</layer>
<layer>resources</layer>
<layer>snapshots</layer>
<layer>company-dependencies</layer>
<layer>dependencies</layer>
</layers>
<libraries>
<layer-content layer="snapshot-dependencies">
<coordinates>
<include>*:*:*SNAPSHOT</include>
</coordinates>
</layer-content>
<layer-content layer="company-dependencies">
<coordinates>
<include>com.acme:*</include>
</coordinates>
</layer-content>
<layer-content layer="dependencies">
<coordinates>
<include>*:*</include>
</coordinates>
</layer-content>
</libraries>
<application> <application>
... <into layer="spring-boot-loader">
<include>org/springframework/boot/loader/**</include>
</into>
<into layer="application" />
</application> </application>
</layers-configuration> <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>
---- ----
The configuration above creates an additional `company-dependencies` layer with all libraries with the `com.acme` groupId. The configuration above creates an additional `company-dependencies` layer with all libraries with the `com.acme` groupId.

Loading…
Cancel
Save