54. 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.

54.1 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:1.1.1.RELEASE")
    }
}
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"
    }
    // ...
}

54.2 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. To make use of this functionality, 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")
}
[Note]Note

The version of the spring-boot gradle plugin that you declare determines the actual versions of the “blessed” dependencies (this ensures that builds are always repeatable). You should always set the version of the spring-boot gradle plugin to the actual Spring Boot version that you wish to use. Details of the versions that are provided can be found in the appendix.

The spring-boot plugin will only supply a version where one is not specified. To use a version of an artifact that differs from the one that the plugin would provide, simply specify the version when you declare the dependency as you usually would. For example:

dependencies {
    compile("org.thymeleaf:thymeleaf-spring4:2.1.1.RELEASE")
}

54.2.1 Custom version management

If is possible to customize the versions used by the ResolutionStrategy if you need to deviate from Spring Boot’s “blessed” dependencies. Alternative version meta-data is consulted using the versionManagement configuration. For example:

dependencies {
    versionManagement("com.mycorp:mycorp-versions:1.0.0.RELEASE@properties")
    compile("org.springframework.data:spring-data-hadoop")
}

Version information needs to be published to a repository as a .properties file. For the above example mycorp-versions.properties file might contain the following:

org.springframework.data\:spring-data-hadoop=2.0.0.RELEASE

The properties file takes precedence over Spring Boot’s defaults, and can be used to override version numbers if necessary.

54.3 Default exclude rules

Gradle handles “exclude rules” in a slightly different way to Maven which can cause unexpected results when using the starter POMs. Specifically, exclusions declared on a dependency will not be applied when the dependency can be reached though a different path. For example, if a starter POM declares the following:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.0.5.RELEASE</version>
        <exclusions>
            <exclusion>
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.0.5.RELEASE</version>
    </dependency>
</dependencies>

The commons-logging jar will not be excluded by Gradle because it is pulled in transitively via spring-context (spring-contextspring-corecommons-logging) which does not have an exclusion element.

To ensure that correct exclusions are actually applied, the Spring Boot Gradle plugin will automatically add exclusion rules. All exclusions defined in the spring-boot-dependencies POM and the “starter” POMs will be added (both direct and transitive exclusions).

If you don’t want exclusion rules automatically applied you can use the following configuration:

springBoot {
    applyExcludeRules=false
}

54.4 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")
    ...
}

54.5 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.

54.6 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
}

54.7 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.

54.7.1 Configuration options

The following configuration options are available:

NameDescription

mainClass

The main class that should be run. If not specified the mainClassName project property will be used or, if the no mainClassName id defined 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).

54.8 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.