Combine application and resources layers into a single layer
Closes gh-20562
This commit is contained in:
		
							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…
	
		Reference in New Issue