Reusing Spring Boot’s Dependency Management
If you develop a Spring Boot application and are using Gradle, you have already used the Spring Boot Gradle plugin. It serves several different purposes such as packaging your project to an executable jar (or war) file, executing the project and it also takes care of version management of third party dependencies. The aim of this blog post is to explain how you can utilize the dependency management plugin in a multi module Gradle project where one submodule neither uses the Spring Boot Gradle plugin, nor has a transitive dependency to Spring Boot. Yet, it is able to use the same version of a dependency that is defined by Spring Boot’s version management.
Example Project
A simplified Gradle project has two submodules:
- The 
alphamodule is a standard Java project that has a single Spring framework dependency, see alpha’s build.gradle file. - The 
betamodule is an executable project that depends onalpha, the same Spring framework dependency as well as Spring Boot dependency, see beta’s build.gradle file. 
Project layout:
parent
|
+--- build.gradle
+--- gradle.properties
+--- settings.gradle
|
+--- alpha
|    |
|    +--- build.gradle
|    \--- src/main/java/alpha/Alpha.java
|
\--- beta
     |
     +--- build.gradle
     \--- src/main/java/beta/Beta.java
Now the challenge is to make sure that the alpha and beta project the same version of Spring (and possibly other third party libraries that have been “blessed” by Spring Boot) without having to define the version numbers manually or rely on transitive dependency management. In this particular example, you will find that the 4.2.3-RELEASE of spring-context version is used in both submodules, despite that the version number is never defined in the source code.
Dependency Management
There is a lot of valuable information in the Spring Boot reference guide regarding dependency management. First, you will find that the Spring Boot Gradle plugin uses the dependency management provided by spring-boot-dependencies, a Maven BOM file provided by Spring Boot. As such, it contains dependency definitions and corresponding version numbers without actually including them to your project (basically, it is a Maven pom.xml file that has pom as <packaging> and a range of curated dependencies listed in the <dependencyManagement> element. If you are interested, you can take a closer look at how this is done in the spring-boot-dependencies pom.xml file at GitHub). Secondly, you will find that the Spring Boot Gradle plugin uses the Dependency Management Plugin behind the scenes. This is something that we will take advantage of when we import the Maven BOM file. Finally, there is an example of how a build.gradle file may look like for single module projects. With these facts at hand, we can create a build.gradle file for the parent project.
Parent build.gradle
The key takeaway of this blog post is the resulting build.gradle file in the parent module. As we will see later, this will make the submodules build.gradle files very succinct. Here it is being presented in its entirety, but you can scroll down to read explanations for each // #nbr.
// 1
buildscript {
    repositories {
        // 2
        jcenter()
    }
    // 3
    dependencies {
        classpath('io.spring.gradle:dependency-management-plugin:0.5.3.RELEASE')
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}
// 4
subprojects {
    repositories {
        // 5
        jcenter()
    }
    // 6
    apply plugin: 'java'
    apply plugin: 'io.spring.dependency-management'
    dependencyManagement {
        imports {
            // 7
            mavenBom("org.springframework.boot:spring-boot-dependencies:${springBootVersion}")
        }
    }
}
Explanations
- The buildScript method is used if your Gradle build script uses external plugins such as the 
dependency-management-pluginand thespring-boot-gradle-plugin. - Define which Maven repository should be used to download external Gradle plugins. 
jcenter()points to a Maven repository provided by Bintray located available at https://bintray.com/bintray/jcenter. - Add the two external Gradle plugins to the buildscript classpath so that they can be used by the buildscript itself. The 
${springBootVersion}is specified in the gradle.properties file so that it can be re-used. - The 
subprojectsmethod allow us to define configuration that is shared between all subprojects, i.e.alphaandbetain this example (side note, Gradle also has anallprojectsmethod). - Repeat 
repositoriesmethod, this time for defining the location(s) of the project dependencies. - Apply the dependency management plugin.
 - Declare which Maven BOM to import. Specifically for this example, you will find that the spring-boot-dependencies pom.xml file mentioned earlier has a 
<spring.version>4.2.3.RELEASE</spring.version>property in addition to the declaration of thespring-coredependency. 
Code Snippets
Alpha’s build.gradle. Note that we do not specify which version of spring-context is used. It is handled by the mavenBom import of the spring-boot-dependencies in the Parent build.gradle.
dependencies {
    compile('org.springframework:spring-context')
}
Beta’s build.gradle. Neither the version of spring-context nor spring-boot-starter need to be specified, but the spring-boot plugin has been added so that the module can be executed and packaged as an executable jar.
apply plugin: 'spring-boot'
dependencies {
    compile project(':alpha')
    compile('org.springframework:spring-context')
    compile('org.springframework.boot:spring-boot-starter')
}
Shared gradle.properties
springBootVersion = 1.3.0.RELEASE
The project’s settings.gradle
include 'alpha'
include 'beta'
Java classes
package alpha;
import org.springframework.stereotype.Component;
@Component
public class Alpha {
    public String hello() {
        return "Hello from Alpha!";
    }
}
package beta;
import alpha.Alpha;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication(scanBasePackages = {"alpha", "beta"})
public class Beta {
    public static void main(String[] args) {
        SpringApplication.run(Beta.class, args);
    }
    @Bean
    CommandLineRunner commandLineRunner(Alpha alpha) {
        return args -> System.out.println(alpha.hello());
    }
}
Executions
Listing of alpha’s dependencies:
$ gradle alpha:dependencies
[...]
default - Configuration for default artifacts.
\--- org.springframework:spring-context: -> 4.2.3.RELEASE
[...]
Listing of beta’s dependencies:
$ gradle beta:dependencies
[...]
default - Configuration for default artifacts.
+--- project :alpha
|    \--- org.springframework:spring-context: -> 4.2.3.RELEASE
[...]
+--- org.springframework:spring-context: -> 4.2.3.RELEASE (*)
\--- org.springframework.boot:spring-boot-starter: -> 1.3.0.RELEASE
[...]
(*) - dependencies omitted (listed previously)
Project execution:
$ gradle beta:bootRun
[...]
Hello from Alpha!
[...]
Acknowledgements
Thanks to Opal for answering my question at Stack Overflow.
References
- Better dependency management for Gradle Spring blog post.
 - Dependency Management chapter, Spring Boot reference.
 - Gradle chapter, Spring Boot reference guide.
 - Spring Boot Gradle plugin.
 - Gradle dependency management chapter, Spring Boot reference guide.
 - Dependency management plugin.
 - Dependency versions of third party dependencies defined in Spring Boot version 1.3.