Combine application and resources layers into a single layer

Closes gh-20562
pull/20628/head
Madhura Bhave 5 years ago
parent 952e529787
commit a06f4f21e3

@ -284,11 +284,10 @@ By default, the following layers are created:
* `dependencies` for any dependency whose version does not contain `SNAPSHOT`. * `dependencies` for any dependency whose version does not contain `SNAPSHOT`.
* `snapshot-dependencies` for any dependency whose version contains `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 application classes and resources.
* `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 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`. The default order is `dependencies`, `snapshot-dependencies`, and `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-layertools` jar will be added as a dependency to your jar. When you create a layered jar, the `spring-boot-layertools` jar will be added as a dependency to your jar.
@ -328,7 +327,7 @@ 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. 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. 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. 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 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]`. The format is `groupId:artifactId[:version]`.

@ -10,7 +10,7 @@ bootJar {
// tag::layered[] // tag::layered[]
bootJar { bootJar {
layers { layers {
layersOrder "dependencies", "snapshot-dependencies", "resources", "application" layersOrder "dependencies", "snapshot-dependencies", "application"
libraries { libraries {
layerContent("snapshot-dependencies") { layerContent("snapshot-dependencies") {
coordinates { coordinates {
@ -24,12 +24,6 @@ bootJar {
} }
} }
application { application {
layerContent("resources") {
locations {
include "META-INF/resources/**", "resources/**"
include "static/**", "public/**"
}
}
layerContent("application") { layerContent("application") {
locations { locations {
include "**" include "**"

@ -8,7 +8,7 @@ plugins {
// tag::layered[] // tag::layered[]
tasks.getByName<BootJar>("bootJar") { tasks.getByName<BootJar>("bootJar") {
layers { layers {
layersOrder("dependencies", "snapshot-dependencies", "resources", "application") layersOrder("dependencies", "snapshot-dependencies", "application")
libraries { libraries {
layerContent("snapshot-dependencies") { layerContent("snapshot-dependencies") {
coordinates { coordinates {
@ -22,12 +22,6 @@ tasks.getByName<BootJar>("bootJar") {
} }
} }
application { application {
layerContent("resources") {
locations {
include("META-INF/resources/**", "resources/**")
include("static/**", "public/**")
}
}
layerContent("application") { layerContent("application") {
locations { locations {
include("**") include("**")

@ -81,7 +81,7 @@ class BootJarIntegrationTests extends AbstractBootArchiveIntegrationTests {
assertThat(jarFile.getEntry("BOOT-INF/layers/snapshot-dependencies/lib/commons-io-2.7-SNAPSHOT.jar")) assertThat(jarFile.getEntry("BOOT-INF/layers/snapshot-dependencies/lib/commons-io-2.7-SNAPSHOT.jar"))
.isNotNull(); .isNotNull();
assertThat(jarFile.getEntry("BOOT-INF/layers/application/classes/example/Main.class")).isNotNull(); assertThat(jarFile.getEntry("BOOT-INF/layers/application/classes/example/Main.class")).isNotNull();
assertThat(jarFile.getEntry("BOOT-INF/layers/resources/classes/static/file.txt")).isNotNull(); assertThat(jarFile.getEntry("BOOT-INF/layers/application/classes/static/file.txt")).isNotNull();
} }
} }

@ -103,7 +103,7 @@ class BootJarTests extends AbstractBootArchiveTests<BootJar> {
void whenJarIsLayeredThenLayersIndexIsPresentAndListsLayersInOrder() throws IOException { void whenJarIsLayeredThenLayersIndexIsPresentAndListsLayersInOrder() throws IOException {
try (JarFile jarFile = new JarFile(createLayeredJar())) { try (JarFile jarFile = new JarFile(createLayeredJar())) {
assertThat(entryLines(jarFile, "BOOT-INF/layers.idx")).containsExactly("dependencies", assertThat(entryLines(jarFile, "BOOT-INF/layers.idx")).containsExactly("dependencies",
"snapshot-dependencies", "resources", "application"); "snapshot-dependencies", "application");
} }
} }
@ -116,7 +116,7 @@ class BootJarTests extends AbstractBootArchiveTests<BootJar> {
.contains("BOOT-INF/layers/snapshot-dependencies/lib/third-library-SNAPSHOT.jar") .contains("BOOT-INF/layers/snapshot-dependencies/lib/third-library-SNAPSHOT.jar")
.containsSubsequence("BOOT-INF/layers/application/classes/com/example/Application.class", .containsSubsequence("BOOT-INF/layers/application/classes/com/example/Application.class",
"BOOT-INF/layers/application/classes/application.properties") "BOOT-INF/layers/application/classes/application.properties")
.contains("BOOT-INF/layers/resources/classes/static/test.css"); .contains("BOOT-INF/layers/application/classes/static/test.css");
} }
@Test @Test

@ -24,13 +24,8 @@ package org.springframework.boot.loader.tools;
*/ */
class ImplicitLayerResolver extends StandardLayers { class ImplicitLayerResolver extends StandardLayers {
private static final String[] RESOURCE_LOCATIONS = { "META-INF/resources/", "resources/", "static/", "public/" };
@Override @Override
public Layer getLayer(String name) { public Layer getLayer(String name) {
if (!isClassFile(name) && isInResourceLocation(name)) {
return RESOURCES;
}
return APPLICATION; return APPLICATION;
} }
@ -42,17 +37,4 @@ class ImplicitLayerResolver extends StandardLayers {
return DEPENDENCIES; return DEPENDENCIES;
} }
private boolean isClassFile(String name) {
return name.endsWith(".class");
}
private boolean isInResourceLocation(String name) {
for (String resourceLocation : RESOURCE_LOCATIONS) {
if (name.startsWith(resourceLocation)) {
return true;
}
}
return false;
}
} }

@ -26,7 +26,6 @@ import java.util.List;
* <ol> * <ol>
* <li>"dependencies" - For non snapshot dependencies</li> * <li>"dependencies" - For non snapshot dependencies</li>
* <li>"snapshot-dependencies" - For snapshot dependencies</li> * <li>"snapshot-dependencies" - For snapshot dependencies</li>
* <li>"resources" - For static resources such as HTML files</li>
* <li>"application" - For application classes and resources</li> * <li>"application" - For application classes and resources</li>
* </ol> * </ol>
* *
@ -46,11 +45,6 @@ public abstract class StandardLayers implements Layers {
*/ */
public static final Layer SNAPSHOT_DEPENDENCIES = new Layer("snapshot-dependencies"); public static final Layer SNAPSHOT_DEPENDENCIES = new Layer("snapshot-dependencies");
/**
* The resources layer.
*/
public static final Layer RESOURCES = new Layer("resources");
/** /**
* The application layer. * The application layer.
*/ */
@ -61,7 +55,6 @@ public abstract class StandardLayers implements Layers {
List<Layer> layers = new ArrayList<>(); List<Layer> layers = new ArrayList<>();
layers.add(DEPENDENCIES); layers.add(DEPENDENCIES);
layers.add(SNAPSHOT_DEPENDENCIES); layers.add(SNAPSHOT_DEPENDENCIES);
layers.add(RESOURCES);
layers.add(APPLICATION); layers.add(APPLICATION);
LAYERS = Collections.unmodifiableList(layers); LAYERS = Collections.unmodifiableList(layers);
} }

@ -35,15 +35,15 @@ class ImplicitLayerResolverTests {
@Test @Test
void iteratorReturnsLayers() { void iteratorReturnsLayers() {
assertThat(this.layers).containsExactly(StandardLayers.DEPENDENCIES, StandardLayers.SNAPSHOT_DEPENDENCIES, assertThat(this.layers).containsExactly(StandardLayers.DEPENDENCIES, StandardLayers.SNAPSHOT_DEPENDENCIES,
StandardLayers.RESOURCES, StandardLayers.APPLICATION); StandardLayers.APPLICATION);
} }
@Test @Test
void getLayerWhenNameInResourceLocationReturnsResourceLayer() { void getLayerWhenNameInResourceLocationReturnsApplicationLayer() {
assertThat(this.layers.getLayer("META-INF/resources/logo.gif")).isEqualTo(StandardLayers.RESOURCES); assertThat(this.layers.getLayer("META-INF/resources/logo.gif")).isEqualTo(StandardLayers.APPLICATION);
assertThat(this.layers.getLayer("resources/logo.gif")).isEqualTo(StandardLayers.RESOURCES); assertThat(this.layers.getLayer("resources/logo.gif")).isEqualTo(StandardLayers.APPLICATION);
assertThat(this.layers.getLayer("static/logo.gif")).isEqualTo(StandardLayers.RESOURCES); assertThat(this.layers.getLayer("static/logo.gif")).isEqualTo(StandardLayers.APPLICATION);
assertThat(this.layers.getLayer("public/logo.gif")).isEqualTo(StandardLayers.RESOURCES); assertThat(this.layers.getLayer("public/logo.gif")).isEqualTo(StandardLayers.APPLICATION);
} }
@Test @Test

@ -102,11 +102,10 @@ By default, the following layers are created:
* `dependencies` for any dependency whose version does not contain `SNAPSHOT`. * `dependencies` for any dependency whose version does not contain `SNAPSHOT`.
* `snapshot-dependencies` for any dependency whose version contains `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 application classes and resources.
* `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 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`. The default order is `dependencies`, `snapshot-dependencies`, and `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.
@ -149,7 +148,6 @@ The following example shows what the implicit layer configuration described abov
<layers> <layers>
<layer>dependencies</layer> <layer>dependencies</layer>
<layer>snapshot-dependencies</layer> <layer>snapshot-dependencies</layer>
<layer>resources</layer>
<layer>application</layer> <layer>application</layer>
</layers> </layers>
<libraries> <libraries>
@ -165,14 +163,6 @@ The following example shows what the implicit layer configuration described abov
</layer-content> </layer-content>
</libraries> </libraries>
<application> <application>
<layer-content layer="resources">
<locations>
<include>META-INF/resources/**</include>
<include>resources/**</include>
<include>static/**</include>
<include>public/**</include>
</locations>
</layer-content>
<layer-content layer="application"> <layer-content layer="application">
<locations> <locations>
<include>**</include> <include>**</include>
@ -184,7 +174,7 @@ The following example shows what the implicit layer configuration described abov
Each `layer-content` element defines a strategy to include or exclude an entry of the jar in a layer. 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. 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. 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 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]`. The format is `groupId:artifactId[:version]`.

Loading…
Cancel
Save