Add support for customizing layers in Gradle

This commit adds configuration to the Spring Boot Gradle plugin that
allows the names and contents of layers to be customized in the build
configuration.

Fixes gh-20296
This commit is contained in:
Scott Frederick
2020-03-10 16:09:44 -07:00
parent c4a55a5fb4
commit f2dadf5a87
23 changed files with 643 additions and 59 deletions

View File

@@ -264,7 +264,7 @@ include::../gradle/packaging/boot-war-properties-launcher.gradle.kts[tags=proper
[[packaging-layered-jars]]
==== Packaging layered jars
By default, the `bootJar` tasks 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.
To use this feature, the layering feature must be enabled:
@@ -280,12 +280,16 @@ include::../gradle/packaging/boot-jar-layered.gradle[tags=layered]
include::../gradle/packaging/boot-jar-layered.gradle.kts[tags=layered]
----
The jar will then be split into layer folders which may include:
By default, the following layers are created:
* `application`
* `resources`
* `snapshots-dependencies`
* `dependencies`
* `dependencies` for any dependency whose version does not contain `SNAPSHOT`.
* `snapshot-dependencies` for any dependency whose version contains `SNAPSHOT`.
* `resources` for static resources at the default locations, i.e. `META-INF/resources/`, `resources/`, `static/`, `public/`.
* `application` for any other 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`, `resources`, and `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-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.
@@ -301,4 +305,33 @@ include::../gradle/packaging/boot-jar-layered-exclude-tools.gradle[tags=layered]
.Kotlin
----
include::../gradle/packaging/boot-jar-layered-exclude-tools.gradle.kts[tags=layered]
----
----
[[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.
This is illustrated by the `dependencies` and `application` layers that have a "catch-all" include filter used to add any libraries or classes 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 content of a `classes` layer can be customized using filters to `included` or `exclude` based on location of the entry using Ant-style pattern matching.

View File

@@ -0,0 +1,41 @@
plugins {
id 'java'
id 'org.springframework.boot' version '{version}'
}
bootJar {
mainClassName 'com.example.ExampleApplication'
}
// tag::layered[]
bootJar {
layers {
layers "dependencies", "snapshot-dependencies", "resources", "application"
libraries {
layerContent("snapshot-dependencies") {
coordinates {
include "*:*:*SNAPSHOT"
}
}
layerContent("dependencies") {
coordinates {
include "*:*"
}
}
}
classes {
layerContent("resources") {
locations {
include "META-INF/resources/**", "resources/**"
include "static/**", "public/**"
}
}
layerContent("application") {
locations {
include "**"
}
}
}
}
}
// end::layered[]

View File

@@ -0,0 +1,40 @@
import org.springframework.boot.gradle.tasks.bundling.BootJar
plugins {
java
id("org.springframework.boot") version "{version}"
}
// tag::layered[]
tasks.getByName<BootJar>("bootJar") {
layers {
includeLayerTools = false
layers("dependencies", "snapshot-dependencies", "resources", "application")
libraries {
layerContent("snapshot-dependencies") {
coordinates {
include("*:*:*SNAPSHOT")
}
}
layerContent("dependencies") {
coordinates {
include("*:*")
}
}
}
classes {
layerContent("resources") {
locations {
include("META-INF/resources/**", "resources/**")
include("static/**", "public/**")
}
}
layerContent("application") {
locations {
include("**")
}
}
}
}
}
// end::layered[]

View File

@@ -9,7 +9,7 @@ bootJar {
// tag::layered[]
bootJar {
layered {
layers {
includeLayerTools = false
}
}

View File

@@ -11,7 +11,7 @@ tasks.getByName<BootJar>("bootJar") {
// tag::layered[]
tasks.getByName<BootJar>("bootJar") {
layered {
layers {
includeLayerTools = false
}
}

View File

@@ -9,6 +9,6 @@ bootJar {
// tag::layered[]
bootJar {
layered()
layers()
}
// end::layered[]

View File

@@ -11,6 +11,6 @@ tasks.getByName<BootJar>("bootJar") {
// tag::layered[]
tasks.getByName<BootJar>("bootJar") {
layered()
layers()
}
// end::layered[]