From 12bc890e756673c54d94b3674134cdca530b1afc Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Thu, 2 Apr 2020 23:33:34 -0700 Subject: [PATCH] Update Maven and Gradle layer customization docs Update the Maven and Gradle documentation following the refined layer customization changes. See gh-20526 --- .../docs/asciidoc/spring-boot-features.adoc | 2 +- .../src/docs/asciidoc/packaging.adoc | 45 +++-- .../packaging/boot-jar-layered-custom.gradle | 5 +- .../boot-jar-layered-custom.gradle.kts | 5 +- .../src/docs/asciidoc/packaging.adoc | 159 +++++++++--------- 5 files changed, 126 insertions(+), 90 deletions(-) diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc index f47e78b09a35..737b8d34e09f 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc @@ -8031,7 +8031,7 @@ For Gradle, refer to the {spring-boot-gradle-plugin-docs}/#packaging-layered-jar === 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. Here’s how you can launch your jar with a `layertools` jar mode: diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/asciidoc/packaging.adoc b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/asciidoc/packaging.adoc index 8695aa9705ab..fcaede2e067c 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/asciidoc/packaging.adoc +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/asciidoc/packaging.adoc @@ -265,7 +265,9 @@ include::../gradle/packaging/boot-war-properties-launcher.gradle.kts[tags=proper [[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. -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: [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] ---- -By default, the following layers are created: +By default, the following layers are defined: * `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`. * `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 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. 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]] ===== 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: +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"] .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] ---- -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. -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 `layered` DSL is defined using three parts: + +* 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 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` closure 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. -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. \ No newline at end of file +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. diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/gradle/packaging/boot-jar-layered-custom.gradle b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/gradle/packaging/boot-jar-layered-custom.gradle index 2fb89c7d5f9b..d0465880e948 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/gradle/packaging/boot-jar-layered-custom.gradle +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/gradle/packaging/boot-jar-layered-custom.gradle @@ -11,6 +11,9 @@ bootJar { bootJar { layered { application { + intoLayer("spring-boot-loader") { + include "org/springframework/boot/loader/**" + } intoLayer("application") } dependencies { @@ -19,7 +22,7 @@ bootJar { } intoLayer("dependencies") } - layerOrder "dependencies", "snapshot-dependencies", "application" + layerOrder "dependencies", "spring-boot-loader", "snapshot-dependencies", "application" } } // end::layered[] diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/gradle/packaging/boot-jar-layered-custom.gradle.kts b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/gradle/packaging/boot-jar-layered-custom.gradle.kts index a438e395a17b..a71a1aca7ba2 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/gradle/packaging/boot-jar-layered-custom.gradle.kts +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/gradle/packaging/boot-jar-layered-custom.gradle.kts @@ -9,6 +9,9 @@ plugins { tasks.getByName("bootJar") { layered { application { + intoLayer("spring-boot-loader") { + include("org/springframework/boot/loader/**") + } intoLayer("application") } dependencies { @@ -17,7 +20,7 @@ tasks.getByName("bootJar") { } intoLayer("dependencies") { } - layersOrder("dependencies", "snapshot-dependencies", "application") + layersOrder("dependencies", "spring-boot-loader", "snapshot-dependencies", "application") } } // end::layered[] diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/asciidoc/packaging.adoc b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/asciidoc/packaging.adoc index 32bff8f1d823..2623b89894d3 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/asciidoc/packaging.adoc +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/asciidoc/packaging.adoc @@ -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`. * `NONE`: Bundle all dependencies and project resources. Does not bundle a bootstrap loader. + + [[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. -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. +Layered jars use the same layout as regular repackaged jars, but include an additional meta-data file that describes each layer. To use this feature, the layering feature must be enabled: [source,xml,indent=0,subs="verbatim,attributes"] @@ -98,14 +101,15 @@ To use this feature, the layering feature must be enabled: ---- -By default, the following layers are created: +By default, the following layers are defined: * `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`. * `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 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. @@ -113,7 +117,7 @@ Content that is least likely to change should be added first, followed by layers [[repackage-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 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"] ---- @@ -136,53 +140,64 @@ This can be done using a separate configuration file that should be registered a ---- -The configuration file 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: +The configuration file 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,xml,indent=0,subs="verbatim,attributes"] ---- - - - dependencies - snapshot-dependencies - application - - - - + + + + org/springframework/boot/loader/** + + + + + *:*:*SNAPSHOT - - - - - *:* - - - - - - - ** - - - - + + + + + dependencies + spring-boot-loader + snapshot-dependencies + application + + ---- -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 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 `layers` XML format is defined in three sections: + +* The `` block defines how the application classes and resources should be layered. +* The `` block defines how dependencies should be layered. +* The `` block defines the order that the layers should be written. + +Nested `` blocks are used within `` and `` 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 `` block claims content using nested `` and `` elements. +The `` section uses Ant-style patch matching for include/exclude expressions. +The `` 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 `` is defined, then all content (not claimed by an earlier block) is considered. +If no `` is defined, then no exclusions are applied. +Looking at the `` example above, we can see tha the first `` will claim all SNAPSHOT dependencies for the `snapshot-dependencies` layer. +The subsequent `` will claim anything left (in this case, any dependency that is not a SNAPSHOT) for the `dependencies` layer. + +The `` 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 `` blocks are defined is often different from the order that the layers are written. +For this reason the `` element must always be included and _must_ cover all layers referenced by the `` blocks. 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]] ==== Layered jar tools - 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. 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]] ==== Custom layers configuration - -While the default setup creates two layers for libraries, you may want to isolate the 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 default setup splits dependencies into snaphost and non-snapshot, however, you may have more complex rules. +For example, you may want to isolate company-specific dependencies of your project in a dedicated layer. +The following `layers.xml` configuration shown one such setup: [source,xml,indent=0,subs="verbatim,attributes"] ---- - - - application - resources - snapshots - company-dependencies - dependencies - - - - - *:*:*SNAPSHOT - - - - - com.acme:* - - - - - *:* - - - + https://www.springframework.org/schema/boot/layers/layers-{spring-boot-xsd-version}.xsd"> - ... + + org/springframework/boot/loader/** + + - + + + *:*:*SNAPSHOT + + + com.acme:* + + + + + dependencies + spring-boot-loader + snapshot-dependencies + company-dependencies + application + + ---- The configuration above creates an additional `company-dependencies` layer with all libraries with the `com.acme` groupId.