Skip to content

Latest commit

 

History

History
635 lines (492 loc) · 20.7 KB

build-tool-plugins.adoc

File metadata and controls

635 lines (492 loc) · 20.7 KB

Build tool plugins

Spring Boot Maven plugin

The Spring Boot Maven Plugin provides Spring Boot support in Maven, allowing you to package executable jar or war archives and run an application ``in-place''. To use it you must be using Maven 3 (or better).

Including the plugin

To use the Spring Boot Maven Plugin simply include the appropriate XML in the plugins section of your pom.xml

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<!-- ... -->
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<version>{spring-boot-version}</version>
				<executions>
					<execution>
						<goals>
							<goal>repackage</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>

This configuration will repackage a jar or war that is built during the package phase of the Maven lifecycle. The following example shows both the repackaged jar, as well as the original jar, in the target directory:

$ mvn package
$ ls target/*.jar
target/myproject-1.0.0.jar target/myproject-1.0.0.jar.original

If you don’t include the <execution/> configuration as above, you can run the plugin on its own (but only if the package goal is used as well). For example:

$ mvn package spring-boot:repackage
$ ls target/*.jar
target/myproject-1.0.0.jar target/myproject-1.0.0.jar.original

If you are using a milestone or snapshot release you will also need to add appropriate pluginRepository elements:

<pluginRepositories>
	<pluginRepository>
		<id>spring-snapshots</id>
		<url>http://repo.spring.io/snapshot</url>
	</pluginRepository>
	<pluginRepository>
		<id>spring-milestones</id>
		<url>http://repo.spring.io/milestone</url>
	</pluginRepository>
</pluginRepositories>

Packaging executable jar and war files

Once spring-boot-maven-plugin has been included in your pom.xml it will automatically attempt to rewrite archives to make them executable using the spring-boot:repackage goal. You should configure your project to build a jar or war (as appropriate) using the usual packaging element:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<!-- ... -->
	<packaging>jar</packaging>
	<!-- ... -->
</project>

Your existing archive will be enhanced by Spring Boot during the package phase. The main class that you want to launch can either be specified using a configuration option, or by adding a Main-Class attribute to the manifest in the usual way. If you don’t specify a main class the plugin will search for a class with a public static void main(String[] args) method.

To build and run a project artifact, you can type the following:

$ mvn package
$ java -jar target/mymodule-0.0.1-SNAPSHOT.jar

To build a war file that is both executable and deployable into an external container you need to mark the embedded container dependencies as ``provided'', e.g:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<!-- ... -->
	<packaging>war</packaging>
	<!-- ... -->
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
			<scope>provided</scope>
		</dependency>
		<!-- ... -->
	</dependencies>
</project>

Repackage configuration

The following configuration options are available for the spring-boot:repackage goal:

Required parameters

Name Description

outputDirectory

Directory containing the generated archive (defaults to ${project.build.directory}).

finalName

Name of the generated archive (defaults to ${project.build.finalName}).

Optional parameters

Name Description

classifier

Classifier to add to the generated artifact. If given, the artifact will be attached. If this is not given, it will merely be written to the output directory according to the finalName. Attaching the artifact allows to deploy it alongside to the original one, see the maven documentation for more details

mainClass

The name of the main class. If not specified will search for a single compiled class that contains a main method.

layout

The type of archive (which corresponds to how the dependencies are laid out inside it). Defaults to a guess based on the archive type.

The plugin rewrites your manifest, and in particular it manages the Main-Class and Start-Class entries, so if the defaults don’t work you have to configure those there (not in the jar plugin). The Main-Class in the manifest is actually controlled by the layout property of the boot plugin, e.g.

<plugin>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-maven-plugin</artifactId>
	<version>{spring-boot-version}</version>
	<configuration>
		<mainClass>${start-class}</mainClass>
		<layout>ZIP</layout>
	</configuration>
	<executions>
		<execution>
			<goals>
				<goal>repackage</goal>
			</goals>
		</execution>
	</executions>
</plugin>

The layout property defaults to a guess based on the archive type (jar or war). For the PropertiesLauncher the layout is ``ZIP'' (even though the output might be a jar file).

Tip
The executable jar format is described in the appendix.

Running applications

The Spring Boot Maven Plugin includes a run goal which can be used to launch your application from the command line. Type the following from the root of your Maven project:

$ mvn spring-boot:run

By default, any src/main/resources folder will be added to the application classpath when you run via the maven plugin. This allows hot refreshing of resources which can be very useful when developing web applications. For example, you can work on HTML, CSS or JavaScipt files and see your changes immediately without recompiling your application. It is also a helpful way of allowing your front end developers to work without needing to download and install a Java IDE.

Run configuration

The following configuration options are available for the spring-boot:run goal:

Required parameters

Name Description

classesDirectrory

Directory containing the classes and resource files that should be packaged into the archive (defaults to ${project.build.outputDirectory}).

Optional parameters

Name Description

arguments or -Drun.arguments

Arguments that should be passed to the application.

addResources or -Drun.addResources

Add Maven resources to the classpath directly, this allows live in-place editing or resources. Since resources will be added directly, and via the target/classes folder they will appear twice if ClassLoader.getResources() is called. In practice, however, most applications call ClassLoader.getResource() which will always return the first resource (defaults to true).

mainClass

The name of the main class. If not specified the first compiled class found that contains a 'main' method will be used.

folders

Folders that should be added to the classpath (defaults to ${project.build.outputDirectory}).

Spring Boot Gradle plugin

The Spring Boot Gradle Plugin provides Spring Boot support in Gradle, allowing you to package executable jar or war archives, run Spring Boot applications and omit version information from your build.gradle file for ``blessed'' dependencies.

Including the plugin

To use the Spring Boot Gradle Plugin simply include a buildscript dependency and apply the spring-boot plugin:

buildscript {
	dependencies {
		classpath("org.springframework.boot:spring-boot-gradle-plugin:{spring-boot-version}")
	}
}
apply plugin: 'spring-boot'

If you are using a milestone or snapshot release you will also need to add appropriate repositories reference:

buildscript {
	repositories {
		maven.url "http://repo.spring.io/snapshot"
		maven.url "http://repo.spring.io/milestone"
	}
	// ...
}

Declaring dependencies without versions

The spring-boot plugin will register a custom Gradle ResolutionStrategy with your build that allows you to omit version numbers when declaring dependencies to `blessed'' artifacts. All artifacts with a `org.springframework.boot group ID, and any of the artifacts declared in the managementDependencies section of the {github-code}/spring-boot-dependencies/pom.xml[spring-dependencies] POM can have their version number resolved automatically.

Simply declare dependencies in the usual way, but leave the version number empty:

dependencies {
	compile("org.springframework.boot:spring-boot-starter-web")
	compile("org.thymeleaf:thymeleaf-spring4")
	compile("nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect")
}

Packaging executable jar and war files

Once the spring-boot plugin has been applied to your project it will automatically attempt to rewrite archives to make them executable using the bootRepackage task. You should configure your project to build a jar or war (as appropriate) in the usual way.

The main class that you want to launch can either be specified using a configuration option, or by adding a Main-Class attribute to the manifest. If you don’t specify a main class the plugin will search for a class with a public static void main(String[] args) method.

To build and run a project artifact, you can type the following:

$ gradle build
$ java -jar build/libs/mymodule-0.0.1-SNAPSHOT.jar

To build a war file that is both executable and deployable into an external container, you need to mark the embedded container dependencies as belonging to a configuration named "providedRuntime", e.g:

...
apply plugin: 'war'

war {
	baseName = 'myapp'
	version =  '0.5.0'
}

repositories {
	mavenCentral()
	maven { url "http://repo.spring.io/libs-snapshot" }
}

configurations {
	providedRuntime
}

dependencies {
	compile("org.springframework.boot:spring-boot-starter-web")
	providedRuntime("org.springframework.boot:spring-boot-starter-tomcat")
	...
}

Running a project in-place

To run a project in place without building a jar first you can use the "bootRun" task:

$ gradle bootRun

Running this way makes your static classpath resources (i.e. in src/main/resources by default) reloadable in the live application, which can be helpful at development time.

Repackage configuration

The gradle plugin automatically extends your build script DSL with a springBoot element for configuration. Simply set the appropriate properties as you would with any other Gradle extension (see below for a list of configuration options):

springBoot {
	backupSource = false
}

Repackage with custom Gradle configuration

Sometimes it may be more appropriate to not package default dependencies resolved from compile, runtime and provided scopes. If the created executable jar file is intended to be run as it is, you need to have all dependencies nested inside it; however, if the plan is to explode a jar file and run the main class manually, you may already have some of the libraries available via CLASSPATH. This is a situation where you can repackage your jar with a different set of dependencies.

Using a custom configuration will automatically disable dependency resolving from compile, runtime and provided scopes. Custom configuration can be either defined globally (inside the springBoot section) or per task.

task clientJar(type: Jar) {
	appendix = 'client'
	from sourceSets.main.output
	exclude('**/*Something*')
}

task clientBoot(type: BootRepackage, dependsOn: clientJar) {
	withJarTask = clientJar
	customConfiguration = "mycustomconfiguration"
}

In above example, we created a new clientJar Jar task to package a customized file set from your compiled sources. Then we created a new clientBoot BootRepackage task and instructed it to work with only clientJar task and mycustomconfiguration.

configurations {
	mycustomconfiguration.exclude group: 'log4j'
}

dependencies {
	mycustomconfiguration configurations.runtime
}

The configuration that we are referring to in BootRepackage is a normal Gradle configuration. In the above example we created a new configuration named mycustomconfiguration instructing it to derive from a runtime and exclude the log4j group. If the clientBoot task is executed, the repackaged boot jar will have all dependencies from runtime but no log4j jars.

Configuration options

The following configuration options are available:

Name Description

mainClass

The main class that should be run. If not specified the value from the manifest will be used, or if no manifest entry is the archive will be searched for a suitable class.

providedConfiguration

The name of the provided configuration (defaults to providedRuntime).

backupSource

If the original source archive should be backed-up before being repackaged (defaults to true).

customConfiguration

The name of the custom configuration.

layout

The type of archive, corresponding to how the dependencies are laid out inside (defaults to a guess based on the archive type).

Understanding how the Gradle plugin works

When spring-boot is applied to your Gradle project a default task named bootRepackage is created automatically. The bootRepackage task depends on Gradle assemble task, and when executed, it tries to find all jar artifacts whose qualifier is empty (i.e. tests and sources jars are automatically skipped).

Due to the fact that bootRepackage finds 'all' created jar artifacts, the order of Gradle task execution is important. Most projects only create a single jar file, so usually this is not an issue; however, if you are planning to create a more complex project setup, with custom Jar and BootRepackage tasks, there are few tweaks to consider.

If you are 'just' creating custom jar files from your project you can simply disables default jar and bootRepackage tasks:

jar.enabled = false
bootRepackage.enabled = false

Another option is to instruct the default bootRepackage task to only work with a default jar task.

bootRepackage.withJarTask = jar

If you have a default project setup where the main jar file is created and repackaged, 'and' you still want to create additional custom jars, you can combine your custom repackage tasks together and use dependsOn so that the bootJars task will run after the default bootRepackage task is executed:

task bootJars
bootJars.dependsOn = [clientBoot1,clientBoot2,clientBoot3]
build.dependsOn(bootJars)

All the above tweaks are usually used to avoid situations where an already created boot jar is repackaged again. Repackaging an existing boot jar will not break anything, but you may find that it includes unnecessary dependencies.

Supporting other build systems

If you want to use a build tool other than Maven or Gradle, you will likely need to develop your own plugin. Executable jars need to follow a specific format and certain entries need to be written in an uncompressed form (see the 'executable jar format' section in the appendix for details).

The Spring Boot Maven and Gradle plugins both make use of spring-boot-loader-tools to actually generate jars. You are also free to use this library directly yourself if you need to.

Repackaging archives

To repackage an existing archive so that it becomes a self-contained executable archive use org.springframework.boot.loader.tools.Repackager. The Repackager class takes a single constructor argument that refers to an existing jar or war archive. Use one of the two available repackage() methods to either replace the original file or write to a new destination. Various settings can also be configured on the repackager before it is run.

Nested libraries

When repackaging an archive you can include references to dependency files using the org.springframework.boot.loader.tools.Libraries interface. We don’t provide any concrete implementations of Libraries here as they are usually build system specific.

If your archive already includes libraries you can use Libraries.NONE.

Finding a main class

If you don’t use Repackager.setMainClass() to specify a main class, the repackager will use ASM to read class files and attempt to find a suitable class with a public static void main(String[] args) method. An exception is thrown if more than one candidate is found.

Example repackage implementation

Here is a typical example repackage:

Repackager repackager = new Repackager(sourceJarFile);
repackager.setBackupSource(false);
repackager.repackage(new Libraries() {
			@Override
			public void doWithLibraries(LibraryCallback callback) throws IOException {
				// Build system specific implementation, callback for each dependency
				// callback.library(nestedFile, LibraryScope.COMPILE);
			}
		});

What to read next

If your interested to looking at how the build tool plugins were developed you can look at the {github-code}/spring-boot-tools[spring-boot-tools] module on GitHub. More technical details of the executable jar format are covered in the appendix.

If you have specific build related questions, you can check out the `how-to' guides.