Packaging Executable Archives
The plugin can create executable archives (jar files and war files) that contain all of an application’s dependencies and can then be run with java -jar
.
Packaging an executable archive is performed by the repackage
goal, as shown in the following example:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
The repackage goal is not meant to be used alone on the command-line as it operates on the source
jar (or war ) produced by the package phase.
To use this goal on the command-line, you must include the package phase: mvn package spring-boot:repackage .
|
If you are using spring-boot-starter-parent , such execution is already pre-configured with a repackage execution ID so that only the plugin definition should be added.
|
The example above repackages a jar
or war
archive that is built during the package phase of the Maven lifecycle, including any provided
dependencies that are defined in the project.
If some of these dependencies need to be excluded, you can use one of the exclude
options; see the dependency exclusion for more details.
The original (that is non-executable) artifact is renamed to .original
by default but it is also possible to keep the original artifact using a custom classifier.
The outputFileNameMapping feature of the maven-war-plugin is currently not supported.
|
The spring-boot-devtools
and spring-boot-docker-compose
modules are automatically excluded by default (you can control this using the excludeDevtools
and excludeDockerCompose
properties).
In order to make that work with war
packaging, the spring-boot-devtools
and spring-boot-docker-compose
dependencies must be set as optional
or with the provided
scope.
The plugin rewrites your manifest, and in particular it manages the Main-Class
and Start-Class
entries.
If the defaults don’t work you have to configure the values in the Spring Boot plugin, not in the jar plugin.
The Main-Class
in the manifest is controlled by the layout
property of the Spring Boot plugin, as shown in the following example:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>${start.class}</mainClass>
<layout>ZIP</layout>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
The layout
property defaults to a value determined by the archive type (jar
or war
). The following layouts are available:
-
JAR
: regular executable JAR layout. -
WAR
: executable WAR layout.provided
dependencies are placed inWEB-INF/lib-provided
to avoid any clash when thewar
is deployed in a servlet container. -
ZIP
(alias toDIR
): similar to theJAR
layout usingPropertiesLauncher
. -
NONE
: Bundle all dependencies and project resources. Does not bundle a bootstrap loader.
Layered Jar or War
A repackaged jar contains the application’s classes and dependencies in BOOT-INF/classes
and BOOT-INF/lib
respectively.
Similarly, an executable war contains the application’s classes in WEB-INF/classes
and dependencies in WEB-INF/lib
and WEB-INF/lib-provided
.
For cases where a docker image needs to be built from the contents of a jar or war, it’s useful to be able to separate these directories further so that they can be written into distinct layers.
Layered archives use the same layout as a regular repackaged jar or war, but include an additional meta-data file that describes each layer.
By default, the following layers are defined:
-
dependencies
for any dependency whose version does not containSNAPSHOT
. -
spring-boot-loader
for the loader classes. -
snapshot-dependencies
for any dependency whose version containsSNAPSHOT
. -
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
.
Content that is least likely to change should be added first, followed by layers that are more likely to change.
The repackaged archive includes the layers.idx
file by default.
To disable this feature, you can do so in the following manner:
<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<layers>
<enabled>false</enabled>
</layers>
</configuration>
</plugin>
</plugins>
</build>
</project>
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 a separate configuration file that should be registered as shown below:
<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<layers>
<enabled>true</enabled>
<configuration>${project.basedir}/src/layers.xml</configuration>
</layers>
</configuration>
</plugin>
</plugins>
</build>
</project>
The configuration file describes how an archive can be separated into layers, and the order of those layers. The following example shows how the default ordering described above can be defined explicitly:
<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-3.4.xsd">
<application>
<into layer="spring-boot-loader">
<include>org/springframework/boot/loader/**</include>
</into>
<into layer="application" />
</application>
<dependencies>
<into layer="application">
<includeModuleDependencies />
</into>
<into layer="snapshot-dependencies">
<include>*:*:*SNAPSHOT</include>
</into>
<into layer="dependencies" />
</dependencies>
<layerOrder>
<layer>dependencies</layer>
<layer>spring-boot-loader</layer>
<layer>snapshot-dependencies</layer>
<layer>application</layer>
</layerOrder>
</layers>
The layers
XML format is defined in three sections:
-
The
<application>
block defines how the application classes and resources should be layered. -
The
<dependencies>
block defines how dependencies should be layered. -
The
<layerOrder>
block defines the order that the layers should be written.
Nested <into>
blocks are used within <application>
and <dependencies>
sections to claim content for a layer.
The blocks are evaluated in the order that they are defined, from top to bottom.
Any content not claimed by an earlier block remains available for subsequent blocks to consider.
The <into>
block claims content using nested <include>
and <exclude>
elements.
The <application>
section uses Ant-style path 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 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.
Then claiming any remaining classes and resources for the application
layer.
The order that <into> blocks are defined is often different from the order that the layers are written.
For this reason the <layerOrder> element must always be included and must cover all layers referenced by the <into> blocks.
|
spring-boot:repackage
org.springframework.boot:spring-boot-maven-plugin:3.4.1
Repackage existing JAR and WAR archives so that they can be executed from the command line using java -jar
. With layout=NONE
can also be used simply to package a JAR with nested dependencies (and no main class, so not executable).
Optional parameters
Name | Type | Default |
---|---|---|
|
|
|
|
||
|
||
|
||
|
|
|
|
|
|
|
||
|
||
|
|
|
|
|
|
|
|
|
|
||
|
||
|
|
|
|
||
|
|
Parameter details
attach
Attach the repackaged archive to be installed into your local Maven repository or deployed to a remote repository. If no classifier has been configured, it will replace the normal jar. If a classifier
has been configured such that the normal jar and the repackaged jar are different, it will be attached alongside the normal jar. When the property is set to false
, the repackaged archive will not be installed or deployed.
Name |
|
---|---|
Type |
|
Default value |
|
User property |
|
Since |
|
classifier
Classifier to add to the repackaged archive. If not given, the main artifact will be replaced by the repackaged archive. If given, the classifier will also be used to determine the source archive to repackage: if an artifact with that classifier already exists, it will be used as source and replaced. If no such artifact exists, the main artifact will be used as source and the repackaged archive will be attached as a supplemental artifact with that classifier. Attaching the artifact allows to deploy it alongside to the original one, see the Maven documentation for more details.
Name |
|
---|---|
Type |
|
Default value |
|
User property |
|
Since |
|
embeddedLaunchScript
The embedded launch script to prepend to the front of the jar if it is fully executable. If not specified the 'Spring Boot' default script will be used.
Name |
|
---|---|
Type |
|
Default value |
|
User property |
|
Since |
|
embeddedLaunchScriptProperties
Properties that should be expanded in the embedded launch script.
Name |
|
---|---|
Type |
|
Default value |
|
User property |
|
Since |
|
excludeDevtools
Exclude Spring Boot devtools from the repackaged archive.
Name |
|
---|---|
Type |
|
Default value |
|
User property |
|
Since |
|
excludeDockerCompose
Exclude Spring Boot dev services from the repackaged archive.
Name |
|
---|---|
Type |
|
Default value |
|
User property |
|
Since |
|
excludeGroupIds
Comma separated list of groupId names to exclude (exact match).
Name |
|
---|---|
Type |
|
Default value |
|
User property |
|
Since |
|
excludes
Collection of artifact definitions to exclude. The Exclude
element defines mandatory groupId
and artifactId
components and an optional classifier
component. When configured as a property, values should be comma-separated with colon-separated components: groupId:artifactId,groupId:artifactId:classifier
Name |
|
---|---|
Type |
|
Default value |
|
User property |
|
Since |
|
executable
Make a fully executable jar for *nix machines by prepending a launch script to the jar. <p> Currently, some tools do not accept this format so you may not always be able to use this technique. For example, jar -xf
may silently fail to extract a jar or war that has been made fully-executable. It is recommended that you only enable this option if you intend to execute it directly, rather than running it with java -jar
or deploying it to a servlet container.
Name |
|
---|---|
Type |
|
Default value |
|
User property |
|
Since |
|
includeSystemScope
Include system scoped dependencies.
Name |
|
---|---|
Type |
|
Default value |
|
User property |
|
Since |
|
includeTools
Include JAR tools.
Name |
|
---|---|
Type |
|
Default value |
|
User property |
|
Since |
|
includes
Collection of artifact definitions to include. The Include
element defines mandatory groupId
and artifactId
components and an optional classifier
component. When configured as a property, values should be comma-separated with colon-separated components: groupId:artifactId,groupId:artifactId:classifier
Name |
|
---|---|
Type |
|
Default value |
|
User property |
|
Since |
|
layers
Layer configuration with options to disable layer creation, exclude layer tools jar, and provide a custom layers configuration file.
Name |
|
---|---|
Type |
|
Default value |
|
User property |
|
Since |
|
layout
The type of archive (which corresponds to how the dependencies are laid out inside it). Possible values are JAR
, WAR
, ZIP
, DIR
, NONE
. Defaults to a guess based on the archive type.
Name |
|
---|---|
Type |
|
Default value |
|
User property |
|
Since |
|
layoutFactory
The layout factory that will be used to create the executable archive if no explicit layout is set. Alternative layouts implementations can be provided by 3rd parties.
Name |
|
---|---|
Type |
|
Default value |
|
User property |
|
Since |
|
loaderImplementation
The loader implementation that should be used.
Name |
|
---|---|
Type |
|
Default value |
|
User property |
|
Since |
|
mainClass
The name of the main class. If not specified the first compiled class found that contains a main
method will be used.
Name |
|
---|---|
Type |
|
Default value |
|
User property |
|
Since |
|
outputDirectory
Directory containing the generated archive.
Name |
|
---|---|
Type |
|
Default value |
|
User property |
|
Since |
|
outputTimestamp
Timestamp for reproducible output archive entries, either formatted as ISO 8601 (yyyy-MM-dd’T’HH:mm:ssXXX
) or an int
representing seconds since the epoch.
Name |
|
---|---|
Type |
|
Default value |
|
User property |
|
Since |
|
Examples
Custom Classifier
By default, the repackage
goal replaces the original artifact with the repackaged one.
That is a sane behavior for modules that represent an application but if your module is used as a dependency of another module, you need to provide a classifier for the repackaged one.
The reason for that is that application classes are packaged in BOOT-INF/classes
so that the dependent module cannot load a repackaged jar’s classes.
If that is the case or if you prefer to keep the original artifact and attach the repackaged one with a different classifier, configure the plugin as shown in the following example:
<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<classifier>exec</classifier>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
If you are using spring-boot-starter-parent
, the repackage
goal is executed automatically in an execution with id repackage
.
In that setup, only the configuration should be specified, as shown in the following example:
<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>repackage</id>
<configuration>
<classifier>exec</classifier>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
This configuration will generate two artifacts: the original one and the repackaged counter part produced by the repackage goal. Both will be installed/deployed transparently.
You can also use the same configuration if you want to repackage a secondary artifact the same way the main artifact is replaced.
The following configuration installs/deploys a single task
classified artifact with the repackaged application:
<project>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
<phase>package</phase>
<configuration>
<classifier>task</classifier>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<classifier>task</classifier>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
As both the maven-jar-plugin
and the spring-boot-maven-plugin
runs at the same phase, it is important that the jar plugin is defined first (so that it runs before the repackage goal).
Again, if you are using spring-boot-starter-parent
, this can be simplified as follows:
<project>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>default-jar</id>
<configuration>
<classifier>task</classifier>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>repackage</id>
<configuration>
<classifier>task</classifier>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Custom Name
If you need the repackaged jar to have a different local name than the one defined by the artifactId
attribute of the project, use the standard finalName
, as shown in the following example:
<project>
<build>
<finalName>my-app</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
This configuration will generate the repackaged artifact in target/my-app.jar
.
Local Repackaged Artifact
By default, the repackage
goal replaces the original artifact with the executable one.
If you need to only deploy the original jar and yet be able to run your app with the regular file name, configure the plugin as follows:
<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<attach>false</attach>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
This configuration generates two artifacts: the original one and the executable counter part produced by the repackage
goal.
Only the original one will be installed/deployed.
Custom Layout
Spring Boot repackages the jar file for this project using a custom layout factory defined in the additional jar file, provided as a dependency to the build plugin:
<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<layoutFactory implementation="com.example.CustomLayoutFactory">
<customProperty>value</customProperty>
</layoutFactory>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>custom-layout</artifactId>
<version>0.0.1.BUILD-SNAPSHOT</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
The layout factory is provided as an implementation of LayoutFactory
(from spring-boot-loader-tools
) explicitly specified in the pom.
If there is only one custom LayoutFactory
on the plugin classpath and it is listed in META-INF/spring.factories
then it is unnecessary to explicitly set it in the plugin configuration.
Layout factories are always ignored if an explicit layout is set.
Dependency Exclusion
By default, both the repackage
and the run
goals will include any provided
dependencies that are defined in the project.
A Spring Boot project should consider provided
dependencies as "container" dependencies that are required to run the application.
Generally speaking, Spring Boot projects are not used as dependencies and are therefore unlikely to have any optional
dependencies.
When a project does have optional dependencies they too will be included by the repackage
and run
goals.
Some of these dependencies may not be required at all and should be excluded from the executable jar. For consistency, they should not be present either when running the application.
There are two ways one can exclude a dependency from being packaged/used at runtime:
-
Exclude a specific artifact identified by
groupId
andartifactId
, optionally with aclassifier
if needed. -
Exclude any artifact belonging to a given
groupId
.
The following example excludes com.example:module1
, and only that artifact:
<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>com.example</groupId>
<artifactId>module1</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
This example excludes any artifact belonging to the com.example
group:
<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludeGroupIds>com.example</excludeGroupIds>
</configuration>
</plugin>
</plugins>
</build>
</project>
JAR Tools
When a layered jar or war is created, the spring-boot-jarmode-tools
jar will be added as a dependency to your archive.
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.
If you wish to exclude this dependency, you can do so in the following manner:
<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<includeTools>false</includeTools>
</configuration>
</plugin>
</plugins>
</build>
</project>
Custom Layers Configuration
The default setup splits dependencies into snapshot and non-snapshot, however, you may have more complex rules.
For example, you may want to isolate company-specific dependencies of your project in a dedicated layer.
The following layers.xml
configuration shown one such setup:
<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-3.4.xsd">
<application>
<into layer="spring-boot-loader">
<include>org/springframework/boot/loader/**</include>
</into>
<into layer="application" />
</application>
<dependencies>
<into layer="snapshot-dependencies">
<include>*:*:*SNAPSHOT</include>
</into>
<into layer="company-dependencies">
<include>com.acme:*</include>
</into>
<into layer="dependencies"/>
</dependencies>
<layerOrder>
<layer>dependencies</layer>
<layer>spring-boot-loader</layer>
<layer>snapshot-dependencies</layer>
<layer>company-dependencies</layer>
<layer>application</layer>
</layerOrder>
</layers>
The configuration above creates an additional company-dependencies
layer with all libraries with the com.acme
groupId.