Commit 3bfe1b00 authored by Andy Wilkinson's avatar Andy Wilkinson

Put module deps in app layer and make customization easier

Previously, when building a layered jar with Maven, dependencies
on modules in the same build were treated the same as any other
dependency, being included in the dependencies or snapshot dependencies
layer based on their version.

This commit updates the default layering when using Maven to include
dependencies on modules in the same build in the application layer by
default. The XML schema has also been updated to allow the layer to be
customized using new <includeModuleDependencies/> and
<excludeModuleDependencies/> elements rather than relying on including
and excluding them via a group:artifact:version pattern.

Closes gh-23463
parent 5b49986f
......@@ -86,7 +86,10 @@ 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.
* `application` for local module dependencies, application classes, and resources.
Module dependencies are identified by looking at all of the modules that are part of the current build.
If a module dependency can only be resolved because it has been installed into Maven's local cache and it is not part of the current build, it will be identified as regular dependency.
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`, `spring-boot-loader`, `snapshot-dependencies`, `application`.
......@@ -159,6 +162,9 @@ The following example shows how the default ordering described above can be defi
<into layer="application" />
</application>
<dependencies>
<into layer="application">
<includeModuleDependencies />
</into>
<into layer="snapshot-dependencies">
<include>*:*:*SNAPSHOT</include>
</into>
......@@ -187,13 +193,15 @@ Any content not claimed by an earlier block remains available for subsequent blo
The `<into>` block claims content using nested `<include>` and `<exclude>` elements.
The `<application>` section uses Ant-style patch matching for include/exclude expressions.
The `<dependencies>` section uses `group:artifact[:version]` patterns.
It also provides `<includeModuleDependencies />` and `<excludeModuleDependencies />` elements that can be used to include or exclude local module dependencies.
If no `<include>` is defined, then all content (not claimed by an earlier block) is considered.
If no `<exclude>` is defined, then no exclusions are applied.
Looking at the `<dependencies>` example above, we can see that the first `<into>` will claim all SNAPSHOT dependencies for the `snapshot-dependencies` layer.
The subsequent `<into>` will claim anything left (in this case, any dependency that is not a SNAPSHOT) for the `dependencies` layer.
Looking at the `<dependencies>` example above, we can see that the first `<into>` will claim all module dependencies for the `application.layer`.
The next `<into>` will claim all SNAPSHOT dependencies for the `snapshot-dependencies` layer.
The final `<into>` will claim anything left (in this case, any dependency that is not a SNAPSHOT) for the `dependencies` layer.
The `<application>` block has similar rules.
First claiming `org/springframework/boot/loader/**` content for the `spring-boot-loader` layer.
......
......@@ -304,12 +304,13 @@ class JarIntegrationTests extends AbstractArchiveIntegrationTests {
.hasEntryWithNameStartingWith("BOOT-INF/lib/jar-release")
.hasEntryWithNameStartingWith("BOOT-INF/lib/jar-snapshot").hasEntryWithNameStartingWith(
"BOOT-INF/lib/" + JarModeLibrary.LAYER_TOOLS.getCoordinates().getArtifactId());
try {
try (JarFile jarFile = new JarFile(repackaged)) {
Map<String, List<String>> layerIndex = readLayerIndex(jarFile);
assertThat(layerIndex.keySet()).containsExactly("dependencies", "spring-boot-loader",
"snapshot-dependencies", "application");
}
try (JarFile jarFile = new JarFile(repackaged)) {
Map<String, List<String>> layerIndex = readLayerIndex(jarFile);
assertThat(layerIndex.keySet()).containsExactly("dependencies", "spring-boot-loader",
"snapshot-dependencies", "application");
assertThat(layerIndex.get("application")).contains("BOOT-INF/lib/jar-release-0.0.1.RELEASE.jar",
"BOOT-INF/lib/jar-snapshot-0.0.1.BUILD-SNAPSHOT.jar");
assertThat(layerIndex.get("dependencies")).contains("BOOT-INF/lib/log4j-api-2.12.1.jar");
}
catch (IOException ex) {
}
......@@ -351,6 +352,11 @@ class JarIntegrationTests extends AbstractArchiveIntegrationTests {
Map<String, List<String>> layerIndex = readLayerIndex(jarFile);
assertThat(layerIndex.keySet()).containsExactly("my-dependencies-name", "snapshot-dependencies",
"configuration", "application");
assertThat(layerIndex.get("application"))
.contains("BOOT-INF/lib/jar-release-0.0.1.RELEASE.jar",
"BOOT-INF/lib/jar-snapshot-0.0.1.BUILD-SNAPSHOT.jar",
"BOOT-INF/lib/jar-classifier-0.0.1-bravo.jar")
.doesNotContain("BOOT-INF/lib/jar-classifier-0.0.1-alpha.jar");
}
});
}
......
......@@ -170,6 +170,7 @@ class MavenBuild {
request.setUserSettingsFile(new File(this.temp, "settings.xml"));
request.setUpdateSnapshots(true);
request.setBatchMode(true);
// request.setMavenOpts("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8000");
File target = new File(this.temp, "target");
target.mkdirs();
if (this.preparation != null) {
......
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.boot.maven.it</groupId>
<artifactId>jar-classifier</artifactId>
<version>0.0.1</version>
<packaging>jar</packaging>
<name>jar</name>
<description>Classifier Jar dependency</description>
<build>
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>alpha</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>alpha</classifier>
</configuration>
</execution>
<execution>
<id>bravo</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>bravo</classifier>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
......@@ -43,5 +43,16 @@
<artifactId>jar-release</artifactId>
<version>0.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot.maven.it</groupId>
<artifactId>jar-classifier</artifactId>
<version>0.0.1</version>
<classifier>bravo</classifier>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>@log4j2.version@</version>
</dependency>
</dependencies>
</project>
<layers xmlns="http://www.springframework.org/schema/boot/layers"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/boot/layers
https://www.springframework.org/schema/layers/layers-2.3.xsd">
https://www.springframework.org/schema/layers/layers-2.4.xsd">
<application>
<into layer="configuration">
<include>**/application*.*</include>
......@@ -9,6 +9,9 @@
<into layer="application" />
</application>
<dependencies>
<into layer="application">
<includeModuleDependencies />
</into>
<into layer="snapshot-dependencies">
<include>*:*:*-SNAPSHOT</include>
</into>
......
......@@ -12,8 +12,9 @@
<maven.compiler.target>@java.version@</maven.compiler.target>
</properties>
<modules>
<module>jar-snapshot</module>
<module>jar-classifier</module>
<module>jar-release</module>
<module>jar-snapshot</module>
<module>jar</module>
</modules>
</project>
......@@ -27,6 +27,11 @@
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>@log4j2.version@</version>
</dependency>
<dependency>
<groupId>org.springframework.boot.maven.it</groupId>
<artifactId>jar-snapshot</artifactId>
......
......@@ -28,6 +28,7 @@ import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Dependency;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Component;
......@@ -66,6 +67,13 @@ public abstract class AbstractPackagerMojo extends AbstractDependencyFilterMojo
@Parameter(defaultValue = "${project}", readonly = true, required = true)
protected MavenProject project;
/**
* The Maven session.
* @since 2.4.0
*/
@Parameter(defaultValue = "${session}", readonly = true, required = true)
protected MavenSession session;
/**
* Maven project helper utils.
* @since 1.0.0
......@@ -173,7 +181,7 @@ public abstract class AbstractPackagerMojo extends AbstractDependencyFilterMojo
*/
protected final Libraries getLibraries(Collection<Dependency> unpacks) throws MojoExecutionException {
Set<Artifact> artifacts = filterDependencies(this.project.getArtifacts(), getFilters(getAdditionalFilters()));
return new ArtifactsLibraries(artifacts, unpacks, getLog());
return new ArtifactsLibraries(artifacts, this.session.getProjects(), unpacks, getLog());
}
private ArtifactsFilter[] getAdditionalFilters() {
......
......@@ -27,6 +27,7 @@ import java.util.Set;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.model.Dependency;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
import org.springframework.boot.loader.tools.Libraries;
import org.springframework.boot.loader.tools.Library;
......@@ -58,12 +59,38 @@ public class ArtifactsLibraries implements Libraries {
private final Set<Artifact> artifacts;
private final Collection<MavenProject> localProjects;
private final Collection<Dependency> unpacks;
private final Log log;
/**
* Creates a new {@code ArtifactsLibraries} from the given {@code artifacts}.
* @param artifacts the artifacts to represent as libraries
* @param unpacks artifacts that should be unpacked on launch
* @param log the log
* @deprecated since 2.4.0 in favour of
* {@link #ArtifactsLibraries(Set, Collection, Collection, Log)}
*/
@Deprecated
public ArtifactsLibraries(Set<Artifact> artifacts, Collection<Dependency> unpacks, Log log) {
this(artifacts, Collections.emptyList(), unpacks, log);
}
/**
* Creates a new {@code ArtifactsLibraries} from the given {@code artifacts}.
* @param artifacts the artifacts to represent as libraries
* @param localProjects projects for which {@link Library#isLocal() local} libraries
* should be created
* @param unpacks artifacts that should be unpacked on launch
* @param log the log
* @since 2.4.0
*/
public ArtifactsLibraries(Set<Artifact> artifacts, Collection<MavenProject> localProjects,
Collection<Dependency> unpacks, Log log) {
this.artifacts = artifacts;
this.localProjects = localProjects;
this.unpacks = unpacks;
this.log = log;
}
......@@ -81,7 +108,8 @@ public class ArtifactsLibraries implements Libraries {
this.log.debug("Renamed to: " + name);
}
LibraryCoordinates coordinates = new ArtifactLibraryCoordinates(artifact);
callback.library(new Library(name, artifact.getFile(), scope, coordinates, isUnpackRequired(artifact)));
callback.library(new Library(name, artifact.getFile(), scope, coordinates, isUnpackRequired(artifact),
isLocal(artifact)));
}
}
}
......@@ -110,6 +138,20 @@ public class ArtifactsLibraries implements Libraries {
return false;
}
private boolean isLocal(Artifact artifact) {
for (MavenProject localProject : this.localProjects) {
if (localProject.getArtifact().equals(artifact)) {
return true;
}
for (Artifact attachedArtifact : localProject.getAttachedArtifacts()) {
if (attachedArtifact.equals(artifact)) {
return true;
}
}
}
return false;
}
private String getFileName(Artifact artifact) {
StringBuilder sb = new StringBuilder();
sb.append(artifact.getArtifactId()).append("-").append(artifact.getBaseVersion());
......
......@@ -53,11 +53,11 @@ class CustomLayersProvider {
}
private List<ContentSelector<String>> getApplicationSelectors(Element root) {
return getSelectors(root, "application", ApplicationContentFilter::new);
return getSelectors(root, "application", (element) -> getSelector(element, ApplicationContentFilter::new));
}
private List<ContentSelector<Library>> getLibrarySelectors(Element root) {
return getSelectors(root, "dependencies", LibraryContentFilter::new);
return getSelectors(root, "dependencies", (element) -> getLibrarySelector(element, LibraryContentFilter::new));
}
private List<Layer> getLayers(Element root) {
......@@ -69,7 +69,7 @@ class CustomLayersProvider {
}
private <T> List<ContentSelector<T>> getSelectors(Element root, String elementName,
Function<String, ContentFilter<T>> filterFactory) {
Function<Element, ContentSelector<T>> selectorFactory) {
Element element = getChildElement(root, elementName);
if (element == null) {
return Collections.emptyList();
......@@ -79,7 +79,7 @@ class CustomLayersProvider {
for (int i = 0; i < children.getLength(); i++) {
Node child = children.item(i);
if (child instanceof Element) {
ContentSelector<T> selector = getSelector((Element) child, filterFactory);
ContentSelector<T> selector = selectorFactory.apply((Element) child);
selectors.add(selector);
}
}
......@@ -93,6 +93,26 @@ class CustomLayersProvider {
return new IncludeExcludeContentSelector<>(layer, includes, excludes, filterFactory);
}
private <T> ContentSelector<Library> getLibrarySelector(Element element,
Function<String, ContentFilter<Library>> filterFactory) {
Layer layer = new Layer(element.getAttribute("layer"));
List<String> includes = getChildNodeTextContent(element, "include");
List<String> excludes = getChildNodeTextContent(element, "exclude");
Element includeModuleDependencies = getChildElement(element, "includeModuleDependencies");
Element excludeModuleDependencies = getChildElement(element, "excludeModuleDependencies");
List<ContentFilter<Library>> includeFilters = includes.stream().map(filterFactory).collect(Collectors.toList());
if (includeModuleDependencies != null) {
includeFilters = new ArrayList<>(includeFilters);
includeFilters.add(Library::isLocal);
}
List<ContentFilter<Library>> excludeFilters = excludes.stream().map(filterFactory).collect(Collectors.toList());
if (excludeModuleDependencies != null) {
excludeFilters = new ArrayList<>(excludeFilters);
excludeFilters.add(Library::isLocal);
}
return new IncludeExcludeContentSelector<>(layer, includeFilters, excludeFilters);
}
private List<String> getChildNodeTextContent(Element element, String tagName) {
List<String> patterns = new ArrayList<>();
NodeList nodes = element.getElementsByTagName(tagName);
......
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema elementFormDefault="qualified"
xmlns="http://www.springframework.org/schema/boot/layers"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.springframework.org/schema/boot/layers">
<xsd:element name="layers" type="layersType" />
<xsd:complexType name="layersType">
<xsd:sequence>
<xsd:element name="application" type="applicationType" />
<xsd:element name="dependencies" type="dependenciesType" />
<xsd:element name="layerOrder" type="layerOrderType" />
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="applicationType">
<xsd:annotation>
<xsd:documentation><![CDATA[
The 'into layer' selections that should be applied to application classes and resources.
]]></xsd:documentation>
</xsd:annotation>
<xsd:sequence maxOccurs="unbounded">
<xsd:element name="into" type="intoType" />
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="dependenciesType">
<xsd:annotation>
<xsd:documentation><![CDATA[
The 'into layer' selections that should be applied to dependencies.
]]></xsd:documentation>
</xsd:annotation>
<xsd:sequence maxOccurs="unbounded">
<xsd:element name="into" type="dependenciesIntoType" />
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="layerOrderType">
<xsd:annotation>
<xsd:documentation><![CDATA[
The order that layers should be added (starting with the least frequently changed layer).
]]></xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="layer" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation><![CDATA[
The layer name.
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:minLength value="1" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="intoType">
<xsd:choice maxOccurs="unbounded">
<xsd:element type="xsd:string" name="include"
minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation><![CDATA[
Pattern of the elements to include.
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element type="xsd:string" name="exclude"
minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation><![CDATA[
Pattern of the elements to exclude.
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:choice>
<xsd:attribute type="xsd:string" name="layer"
use="required" />
</xsd:complexType>
<xsd:complexType name="dependenciesIntoType">
<xsd:complexContent>
<xsd:extension base="intoType">
<xsd:choice minOccurs="0">
<xsd:element type="xsd:string" name="includeProjectDependencies" minOccurs="0">
<xsd:annotation>
<xsd:documentation><![CDATA[
Include dependencies on other modules in the build.
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element type="xsd:string" name="excludeProjectDependencies" minOccurs="0">
<xsd:annotation>
<xsd:documentation><![CDATA[
Exclude dependencies on other modules in the build.
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:choice>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>
\ No newline at end of file
......@@ -27,6 +27,7 @@ import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.handler.ArtifactHandler;
import org.apache.maven.model.Dependency;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
......@@ -74,7 +75,7 @@ class ArtifactsLibrariesTests {
@BeforeEach
void setup() {
this.artifacts = Collections.singleton(this.artifact);
this.libs = new ArtifactsLibraries(this.artifacts, null, mock(Log.class));
this.libs = new ArtifactsLibraries(this.artifacts, Collections.emptyList(), null, mock(Log.class));
given(this.artifactHandler.getExtension()).willReturn("jar");
}
......@@ -101,7 +102,8 @@ class ArtifactsLibrariesTests {
Dependency unpack = new Dependency();
unpack.setGroupId("gid");
unpack.setArtifactId("aid");
this.libs = new ArtifactsLibraries(this.artifacts, Collections.singleton(unpack), mock(Log.class));
this.libs = new ArtifactsLibraries(this.artifacts, Collections.emptyList(), Collections.singleton(unpack),
mock(Log.class));
this.libs.doWithLibraries(this.callback);
verify(this.callback).library(this.libraryCaptor.capture());
assertThat(this.libraryCaptor.getValue().isUnpackRequired()).isTrue();
......@@ -124,7 +126,7 @@ class ArtifactsLibrariesTests {
given(artifact2.getFile()).willReturn(new File("a"));
given(artifact2.getArtifactHandler()).willReturn(this.artifactHandler);
this.artifacts = new LinkedHashSet<>(Arrays.asList(artifact1, artifact2));
this.libs = new ArtifactsLibraries(this.artifacts, null, mock(Log.class));
this.libs = new ArtifactsLibraries(this.artifacts, Collections.emptyList(), null, mock(Log.class));
this.libs.doWithLibraries(this.callback);
verify(this.callback, times(2)).library(this.libraryCaptor.capture());
assertThat(this.libraryCaptor.getAllValues().get(0).getName()).isEqualTo("g1-artifact-1.0.jar");
......@@ -140,8 +142,43 @@ class ArtifactsLibrariesTests {
given(snapshotArtifact.getFile()).willReturn(new File("a"));
given(snapshotArtifact.getArtifactHandler()).willReturn(this.artifactHandler);
this.artifacts = Collections.singleton(snapshotArtifact);
new ArtifactsLibraries(this.artifacts, null, mock(Log.class)).doWithLibraries(
(library) -> assertThat(library.getCoordinates().getVersion()).isEqualTo("1.0-SNAPSHOT"));
new ArtifactsLibraries(this.artifacts, Collections.emptyList(), null, mock(Log.class))
.doWithLibraries((library) -> {
assertThat(library.isLocal()).isFalse();
assertThat(library.getCoordinates().getVersion()).isEqualTo("1.0-SNAPSHOT");
});
}
@Test
void artifactForLocalProjectProducesLocalLibrary() throws IOException {
Artifact artifact = mock(Artifact.class);
given(artifact.getScope()).willReturn("compile");
given(artifact.getArtifactId()).willReturn("artifact");
given(artifact.getBaseVersion()).willReturn("1.0-SNAPSHOT");
given(artifact.getFile()).willReturn(new File("a"));
given(artifact.getArtifactHandler()).willReturn(this.artifactHandler);
MavenProject mavenProject = mock(MavenProject.class);
given(mavenProject.getArtifact()).willReturn(artifact);
this.artifacts = Collections.singleton(artifact);
new ArtifactsLibraries(this.artifacts, Collections.singleton(mavenProject), null, mock(Log.class))
.doWithLibraries((library) -> assertThat(library.isLocal()).isTrue());
}
@Test
void attachedArtifactForLocalProjectProducesLocalLibrary() throws IOException {
MavenProject mavenProject = mock(MavenProject.class);
Artifact artifact = mock(Artifact.class);
given(mavenProject.getArtifact()).willReturn(artifact);
Artifact attachedArtifact = mock(Artifact.class);
given(attachedArtifact.getScope()).willReturn("compile");
given(attachedArtifact.getArtifactId()).willReturn("attached-artifact");
given(attachedArtifact.getBaseVersion()).willReturn("1.0-SNAPSHOT");
given(attachedArtifact.getFile()).willReturn(new File("a"));
given(attachedArtifact.getArtifactHandler()).willReturn(this.artifactHandler);
given(mavenProject.getAttachedArtifacts()).willReturn(Collections.singletonList(attachedArtifact));
this.artifacts = Collections.singleton(attachedArtifact);
new ArtifactsLibraries(this.artifacts, Collections.singleton(mavenProject), null, mock(Log.class))
.doWithLibraries((library) -> assertThat(library.isLocal()).isTrue());
}
}
......@@ -57,9 +57,12 @@ public class CustomLayersProviderTests {
Library snapshot = mockLibrary("test-SNAPSHOT.jar", "org.foo", "1.0.0-SNAPSHOT");
Library groupId = mockLibrary("my-library", "com.acme", null);
Library otherDependency = mockLibrary("other-library", "org.foo", null);
Library localSnapshotDependency = mockLibrary("local-library", "org.foo", "1.0-SNAPSHOT");
given(localSnapshotDependency.isLocal()).willReturn(true);
assertThat(layers.getLayer(snapshot).toString()).isEqualTo("snapshot-dependencies");
assertThat(layers.getLayer(groupId).toString()).isEqualTo("my-deps");
assertThat(layers.getLayer(otherDependency).toString()).isEqualTo("my-dependencies-name");
assertThat(layers.getLayer(localSnapshotDependency).toString()).isEqualTo("application");
assertThat(layers.getLayer("META-INF/resources/test.css").toString()).isEqualTo("my-resources");
assertThat(layers.getLayer("application.yml").toString()).isEqualTo("configuration");
assertThat(layers.getLayer("test").toString()).isEqualTo("application");
......
<layers xmlns="http://www.springframework.org/schema/boot/layers"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/boot/layers
https://www.springframework.org/schema/boot/layers/layers-2.3.xsd">
https://www.springframework.org/schema/boot/layers/layers-2.4.xsd">
<dependencies>
<into layer="my-deps" />
</dependencies>
......
<layers xmlns="http://www.springframework.org/schema/boot/layers"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/boot/layers
https://www.springframework.org/schema/boot/layers/layers-2.3.xsd">
https://www.springframework.org/schema/boot/layers/layers-2.4.xsd">
<application>
<into layer="my-resources">
<include>META-INF/resources/**</include>
......@@ -15,6 +15,10 @@
<dependencies>
<into layer="snapshot-dependencies">
<include>*:*:*-SNAPSHOT</include>
<excludeModuleDependencies/>
</into>
<into layer="application">
<includeModuleDependencies/>
</into>
<into layer="my-deps">
<include>com.acme:*</include>
......
<layers xmlns="http://www.springframework.org/schema/boot/layers"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/boot/layers
https://www.springframework.org/schema/boot/layers/layers-2.3.xsd">
https://www.springframework.org/schema/boot/layers/layers-2.4.xsd">
<application>
<into layer="my-layer" />
</application>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment