Skip to content

Commit 12bc890

Browse files
committed
Update Maven and Gradle layer customization docs
Update the Maven and Gradle documentation following the refined layer customization changes. See gh-20526
1 parent 0e1394e commit 12bc890

File tree

5 files changed

+126
-90
lines changed

5 files changed

+126
-90
lines changed

spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc

+1-1
Original file line numberDiff line numberDiff line change
@@ -8031,7 +8031,7 @@ For Gradle, refer to the {spring-boot-gradle-plugin-docs}/#packaging-layered-jar
80318031

80328032

80338033
=== Writing the Dockerfile
8034-
When you create a layered jar, the `spring-boot-jarmode-layertools` jar will be added as a dependency to your jar.
8034+
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.
80358035
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.
80368036
Here’s how you can launch your jar with a `layertools` jar mode:
80378037

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/asciidoc/packaging.adoc

+33-12
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,9 @@ include::../gradle/packaging/boot-war-properties-launcher.gradle.kts[tags=proper
265265
[[packaging-layered-jars]]
266266
==== Packaging layered jars
267267
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.
268-
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.
268+
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.
269+
270+
Layered jars use the same layout as regular boot packaged jars, but include an additional meta-data file that describes each layer.
269271
To use this feature, the layering feature must be enabled:
270272

271273
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
@@ -280,14 +282,15 @@ include::../gradle/packaging/boot-jar-layered.gradle[tags=layered]
280282
include::../gradle/packaging/boot-jar-layered.gradle.kts[tags=layered]
281283
----
282284

283-
By default, the following layers are created:
285+
By default, the following layers are defined:
284286

285287
* `dependencies` for any dependency whose version does not contain `SNAPSHOT`.
288+
* `spring-boot-loader` for the jar loader classes.
286289
* `snapshot-dependencies` for any dependency whose version contains `SNAPSHOT`.
287290
* `application` for application classes and resources.
288291

289292
The layers order is important as it determines how likely previous layers can be cached when part of the application changes.
290-
The default order is `dependencies`, `snapshot-dependencies`, and `application`.
293+
The default order is `dependencies`, `spring-boot-loader`, `snapshot-dependencies`, `application`.
291294
Content that is least likely to change should be added first, followed by layers that are more likely to change.
292295

293296
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
311314
[[packaging-layers-configuration]]
312315
===== Custom Layers configuration
313316
Depending on your application, you may want to tune how layers are created and add new ones.
314-
This can be done using configuration that lists the layers and their order as well as the strategies to apply to libraries and classes.
315317

316-
The following example shows what the implicit layer configuration described above does:
318+
This can be done using configuration that describes how the jar can be separated into layers, and the order of those layers.
319+
The following example shows how the default ordering described above can be defined explicity:
317320

318321
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
319322
.Groovy
@@ -327,12 +330,30 @@ include::../gradle/packaging/boot-jar-layered-custom.gradle[tags=layered]
327330
include::../gradle/packaging/boot-jar-layered-custom.gradle.kts[tags=layered]
328331
----
329332

330-
Each `layerContent` closure defines a strategy to include or exclude an entry of the jar in a layer.
331-
When an entry matches a strategy, it is included in the layer and further strategies are ignored.
332-
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.
333+
The `layered` DSL is defined using three parts:
334+
335+
* The `application` closure defines how the application classes and resources should be layered.
336+
* The `dependencies` closure defines how dependencies should be layered.
337+
* The `layerOrder` method defines the order that the layers should be written.
338+
339+
Nested `intoLayer` closures are used within `application` and `dependencies` sections to claim content for a layer.
340+
These closures are evaluated in the order that they are defined, from top to bottom.
341+
Any content not claimed by an earlier `intoLayer` closure remains availble for subsequent ones to consider.
342+
343+
The `intoLayer` closurer claims content using nested `include` and `exclude` calls.
344+
The `applicaton` closure uses Ant-style patch matching for include/exclude parameters.
345+
The `dependencies` section uses `group:artifact[:version]` patterns.
346+
347+
If no `include` call is made, then all content (not claimed by an earlier closure) is considered.
348+
349+
If no `exclude` call is made, then no exclusions are applied.
350+
351+
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.
352+
The subsequent `intoLayer` will claim anything left (in this case, any dependency that is not a SNAPSHOT) for the `dependencies` layer.
333353

334-
The content of a `libraries` layer can be customized using filters to `include` or `exclude` based on the dependency coordinates.
335-
The format is `groupId:artifactId[:version]`.
336-
In the example above, any artifact whose version ends with `SNAPSHOT` is going to be included in the `snapshot-dependencies` layer.
354+
The `application` closure has similar rules.
355+
First claiming `org/springframework/boot/loader/**` content for the `spring-boot-loader` layer.
356+
Then claiming any remaining classes and resources for the `application` layer.
337357

338-
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.
358+
NOTE: The order that `intoLayer` closures are added is often different from the order that the layers are written.
359+
For this reason the `layerOrder` method must always be called and _must_ cover all layers referenced by the `intoLayer` calls.

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/gradle/packaging/boot-jar-layered-custom.gradle

+4-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ bootJar {
1111
bootJar {
1212
layered {
1313
application {
14+
intoLayer("spring-boot-loader") {
15+
include "org/springframework/boot/loader/**"
16+
}
1417
intoLayer("application")
1518
}
1619
dependencies {
@@ -19,7 +22,7 @@ bootJar {
1922
}
2023
intoLayer("dependencies")
2124
}
22-
layerOrder "dependencies", "snapshot-dependencies", "application"
25+
layerOrder "dependencies", "spring-boot-loader", "snapshot-dependencies", "application"
2326
}
2427
}
2528
// end::layered[]

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/gradle/packaging/boot-jar-layered-custom.gradle.kts

+4-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ plugins {
99
tasks.getByName<BootJar>("bootJar") {
1010
layered {
1111
application {
12+
intoLayer("spring-boot-loader") {
13+
include("org/springframework/boot/loader/**")
14+
}
1215
intoLayer("application")
1316
}
1417
dependencies {
@@ -17,7 +20,7 @@ tasks.getByName<BootJar>("bootJar") {
1720
}
1821
intoLayer("dependencies") {
1922
}
20-
layersOrder("dependencies", "snapshot-dependencies", "application")
23+
layersOrder("dependencies", "spring-boot-loader", "snapshot-dependencies", "application")
2124
}
2225
}
2326
// end::layered[]

spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/asciidoc/packaging.adoc

+84-75
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,14 @@ The `layout` property defaults to a guess based on the archive type (`jar` or `w
7171
* `ZIP` (alias to `DIR`): similar to the `JAR` layout using `PropertiesLauncher`.
7272
* `NONE`: Bundle all dependencies and project resources. Does not bundle a bootstrap loader.
7373

74+
75+
7476
[[repackage-layers]]
75-
=== Layered jar
77+
=== Layered jars
78+
A repackaged jar contains the application's classes and dependencies in `BOOT-INF/classes` and `BOOT-INF/lib` respectively.
79+
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.
7680

77-
By default, a repackaged jar contains the application's classes and dependencies in `BOOT-INF/classes` and `BOOT-INF/lib` respectively.
78-
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.
81+
Layered jars use the same layout as regular repackaged jars, but include an additional meta-data file that describes each layer.
7982
To use this feature, the layering feature must be enabled:
8083

8184
[source,xml,indent=0,subs="verbatim,attributes"]
@@ -98,22 +101,23 @@ To use this feature, the layering feature must be enabled:
98101
</project>
99102
----
100103

101-
By default, the following layers are created:
104+
By default, the following layers are defined:
102105

103106
* `dependencies` for any dependency whose version does not contain `SNAPSHOT`.
107+
* `spring-boot-loader` for the jar loader classes.
104108
* `snapshot-dependencies` for any dependency whose version contains `SNAPSHOT`.
105109
* `application` for application classes and resources.
106110

107111
The layers order is important as it determines how likely previous layers can be cached when part of the application changes.
108-
The default order is `dependencies`, `snapshot-dependencies`, and `application`.
112+
The default order is `dependencies`, `spring-boot-loader`, `snapshot-dependencies`, `application`.
109113
Content that is least likely to change should be added first, followed by layers that are more likely to change.
110114

111115

112116

113117
[[repackage-layers-configuration]]
114118
==== Custom Layers configuration
115119
Depending on your application, you may want to tune how layers are created and add new ones.
116-
This can be done using a separate configuration file that should be registered as shown in the following example:
120+
This can be done using a separate configuration file that should be registered as shown below:
117121

118122
[source,xml,indent=0,subs="verbatim,attributes"]
119123
----
@@ -136,53 +140,64 @@ This can be done using a separate configuration file that should be registered a
136140
</project>
137141
----
138142

139-
The configuration file lists the layers and their order as well as the strategies to apply to libraries and classes.
140-
The following example shows what the implicit layer configuration described above does:
143+
The configuration file describes how the jar can be separated into layers, and the order of those layers.
144+
The following example shows how the default ordering described above can be defined explicity:
141145

142146
[source,xml,indent=0,subs="verbatim,attributes"]
143147
----
144-
<layers-configuration xmlns="http://www.springframework.org/schema/boot/layers"
145-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
146-
xsi:schemaLocation="http://www.springframework.org/schema/boot/layers
147-
https://www.springframework.org/schema/boot/layers/layers-configuration-{spring-boot-xsd-version}.xsd">
148-
<layers>
149-
<layer>dependencies</layer>
150-
<layer>snapshot-dependencies</layer>
151-
<layer>application</layer>
152-
</layers>
153-
<libraries>
154-
<layer-content layer="snapshot-dependencies">
155-
<coordinates>
148+
<layers xmlns="http://www.springframework.org/schema/boot/layers"
149+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
150+
xsi:schemaLocation="http://www.springframework.org/schema/boot/layers
151+
https://www.springframework.org/schema/boot/layers/layers-{spring-boot-xsd-version}.xsd">
152+
<application>
153+
<into layer="spring-boot-loader">
154+
<include>org/springframework/boot/loader/**</include>
155+
</into>
156+
<into layer="application" />
157+
</application>
158+
<dependencies>
159+
<into layer="snapshot-dependencies">
156160
<include>*:*:*SNAPSHOT</include>
157-
</coordinates>
158-
</layer-content>
159-
<layer-content layer="dependencies">
160-
<coordinates>
161-
<include>*:*</include>
162-
</coordinates>
163-
</layer-content>
164-
</libraries>
165-
<application>
166-
<layer-content layer="application">
167-
<locations>
168-
<include>**</include>
169-
</locations>
170-
</layer-content>
171-
</application>
172-
</layers-configuration>
161+
</into>
162+
<into layer="dependencies" />
163+
</dependencies>
164+
<layerOrder>
165+
<layer>dependencies</layer>
166+
<layer>spring-boot-loader</layer>
167+
<layer>snapshot-dependencies</layer>
168+
<layer>application</layer>
169+
</layerOrder>
170+
</layers>
173171
----
174172

175-
Each `layer-content` element defines a strategy to include or exclude an entry of the jar in a layer.
176-
When an entry matches a strategy, it is included in the layer and further strategies are ignored.
177-
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.
178173

179-
The content of a `libraries` layer can be customized using filters to `include` or `exclude` based on the dependency coordinates.
180-
The format is `groupId:artifactId[:version]`.
181-
In the example above, any artifact whose version ends with `SNAPSHOT` is going to be included in the `snapshot-dependencies` layer.
174+
The `layers` XML format is defined in three sections:
175+
176+
* The `<application>` block defines how the application classes and resources should be layered.
177+
* The `<dependencies>` block defines how dependencies should be layered.
178+
* The `<layerOrder>` block defines the order that the layers should be written.
179+
180+
Nested `<into>` blocks are used within `<application>` and `<dependencies>` sections to claim content for a layer.
181+
The blocks are evaluated in the order that they are defined, from top to bottom.
182+
Any content not claimed by an earlier block remains availble for subsequent blocks to consider.
183+
184+
The `<into>` block claims content using nested `<include>` and `<exclude>` elements.
185+
The `<applicaton>` section uses Ant-style patch matching for include/exclude expressions.
186+
The `<dependencies>` section uses `group:artifact[:version]` patterns.
182187

183-
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.
188+
If no `<include>` is defined, then all content (not claimed by an earlier block) is considered.
184189

190+
If no `<exclude>` is defined, then no exclusions are applied.
185191

192+
Looking at the `<dependencies>` example above, we can see tha the first `<into>` will claim all SNAPSHOT dependencies for the `snapshot-dependencies` layer.
193+
The subsequent `<into>` will claim anything left (in this case, any dependency that is not a SNAPSHOT) for the `dependencies` layer.
194+
195+
The `<application>` block has similar rules.
196+
First claiming `org/springframework/boot/loader/**` content for the `spring-boot-loader` layer.
197+
Then claiming any remaining classes and resources for the `application` layer.
198+
199+
NOTE: The order that `<into>` blocks are defined is often different from the order that the layers are written.
200+
For this reason the `<layerOrder>` element must always be included and _must_ cover all layers referenced by the `<into>` blocks.
186201

187202
include::goals/repackage.adoc[leveloffset=+1]
188203

@@ -515,7 +530,6 @@ This example excludes any artifact belonging to the `com.foo` group:
515530

516531
[[repackage-layered-jars-tools]]
517532
==== Layered jar tools
518-
519533
When you create a layered jar, the `spring-boot-jarmode-layertools` jar will be added as a dependency to your jar.
520534
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.
521535
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:
545559

546560
[[repackage-layered-jars-additional-layers]]
547561
==== Custom layers configuration
548-
549-
While the default setup creates two layers for libraries, you may want to isolate the dependencies of your project in a dedicated layer.
550-
This allows to reuse the cache for external dependencies when an internal dependency has changed, as shown by the following example:
562+
The default setup splits dependencies into snaphost and non-snapshot, however, you may have more complex rules.
563+
For example, you may want to isolate company-specific dependencies of your project in a dedicated layer.
564+
The following `layers.xml` configuration shown one such setup:
551565

552566
[source,xml,indent=0,subs="verbatim,attributes"]
553567
----
554-
<layers-configuration xmlns="http://www.springframework.org/schema/boot/layers"
568+
<layers xmlns="http://www.springframework.org/schema/boot/layers"
555569
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
556570
xsi:schemaLocation="http://www.springframework.org/schema/boot/layers
557-
https://www.springframework.org/schema/boot/layers/layers-configuration-{spring-boot-xsd-version}.xsd">
558-
<layers>
559-
<layer>application</layer>
560-
<layer>resources</layer>
561-
<layer>snapshots</layer>
562-
<layer>company-dependencies</layer>
563-
<layer>dependencies</layer>
564-
</layers>
565-
<libraries>
566-
<layer-content layer="snapshot-dependencies">
567-
<coordinates>
568-
<include>*:*:*SNAPSHOT</include>
569-
</coordinates>
570-
</layer-content>
571-
<layer-content layer="company-dependencies">
572-
<coordinates>
573-
<include>com.acme:*</include>
574-
</coordinates>
575-
</layer-content>
576-
<layer-content layer="dependencies">
577-
<coordinates>
578-
<include>*:*</include>
579-
</coordinates>
580-
</layer-content>
581-
</libraries>
571+
https://www.springframework.org/schema/boot/layers/layers-{spring-boot-xsd-version}.xsd">
582572
<application>
583-
...
573+
<into layer="spring-boot-loader">
574+
<include>org/springframework/boot/loader/**</include>
575+
</into>
576+
<into layer="application" />
584577
</application>
585-
</layers-configuration>
578+
<dependencies>
579+
<into layer="snapshot-dependencies">
580+
<include>*:*:*SNAPSHOT</include>
581+
</into>
582+
<into layer="company-dependencies">
583+
<include>com.acme:*</include>
584+
</into>
585+
<into layer="dependencies"/>
586+
</dependencies>
587+
<layerOrder>
588+
<layer>dependencies</layer>
589+
<layer>spring-boot-loader</layer>
590+
<layer>snapshot-dependencies</layer>
591+
<layer>company-dependencies</layer>
592+
<layer>application</layer>
593+
</layerOrder>
594+
</layers>
586595
----
587596

588597
The configuration above creates an additional `company-dependencies` layer with all libraries with the `com.acme` groupId.

0 commit comments

Comments
 (0)