Spring Boot Multi-Module Project with Gradle Convention Plugin
Tags: springboot, gradle, kotlin
Published: 2023-08-25 20:22:11

Hi Everyone,
I have been working with Java and Maven for over a decade. Recently, I started migrating many of my projects to Kotlin and Gradle. Most of these projects are multi-module projects with single parent `pom.xml` for dependency management.

During my research I learned that Gradle provides similar organization of modules with convention plugin. However, there seems to be no direct guide or reference to create a working Spring Boot multi-module project with Gradle convention plugin configuration. The references that I found were pretty useful in demonstrating the core concepts but nothing which could be directly applicable to our use case. This is the reason I decided to write this article.

## Project Structure

```
<PROJECT-ROOT>
|   settings.gradle.kts
|                       
+---buildSrc
|   |   build.gradle.kts
|   |   settings.gradle.kts
|   \---src
|       \---main
|           \---kotlin
|                   dev.all_things.reference.spring-boot-parent.gradle.kts
|                   
\---web-app
    |   build.gradle.kts
    |   
    \---src
        \---main
            +---kotlin
            |   \---config
            |           Application.kt
```

## Convention Plugin Configuration

It refers to a build configuration file which defines set of plugins, dependencies and compiler settings. Each file is a Gradle script with `gradle.kts` extension. Gradle will expose each configuration as a plugin with file name as identity e.g. `dev.all_things.reference.spring-boot-parent`.

`buildSrc` is a special directory where all convention plugin configurations reside. This directory is nothing but a standalone Gradle project with its own independent dependency and repository configuration.

Like any standard Gradle project `buildSrc/settings.gradle.kts` specifies repositories required for downloading plugings and dependencies.

```kotlin
// Global plugin management
pluginManagement {
	// Project level repositories for plugins
	repositories {

		// Google mirror of Maven Central for optimized performance
		google()

		// Maven Central (primary) plugin repository
		mavenCentral()

		// Gradle plugin repository
		gradlePluginPortal()
	}
}

// Global dependency management
dependencyResolutionManagement {
	/**
	 * Project level repositories for dependencies.
	 *
	 * Gradle uses its own repository by default.
	 * Maven repository needs to be explicitly configured.
	 */
	repositories {

		// Google mirror of Maven Central for optimized performance
		google()

		// Maven Central (primary) artifact repository
		mavenCentral()
	}
}
```

`buildSrc/build.gradle.kts` specifies common dependencies (and corresponding versions) required by the sub-modules.

```kotlin
description = "kotlin-application-parent"

// Convention plugin configuration
plugins {
	// Enables convention definitions in src/main/kotlin
	`kotlin-dsl`
}

// 'buildSrc' specific dependencies
dependencies {

	// Kotlin
	implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.10")
	implementation("org.jetbrains.kotlin:kotlin-allopen:1.9.10")

	// Spring Boot
	implementation("org.springframework.boot:spring-boot-gradle-plugin:3.1.3")
}
```

Notice that `kotlin-dsl` is configured as a plugin. This enables Kotlin DSL for creating reusable build configurations.

```kotlin
// Convention plugin configuration
plugins {
	// Enables convention definitions in src/main/kotlin
	`kotlin-dsl`
}
```

`dev.all_things.reference.spring-boot-parent.gradle.kts` specifies the actual build configuration that sub-modules can reuse. This file supports all configurations as a standard `build.gradle.kts`.

```kotlin
// Plugins common for sub-modules
plugins {

	// Spring Boot plugin configuration
	id("org.springframework.boot")

	// Spring Boot dependency management configuration
	id("io.spring.dependency-management")

	// Kotlin compiler plugin for JVM
	kotlin("jvm")

	// Kotlin plugin for Spring
	kotlin("plugin.spring")
}

group = "dev.all_things.reference"
version = "1.0.0-SNAPSHOT"

// Enabled by 'Kotlin' plugin
kotlin {

	// JDK specific toolchain configuration
	jvmToolchain(20)

}

// Dependencies common for sub-modules
dependencies {

	// ..
}
```

## Module Configuration

Now that convention configuration is ready, it can be imported by sub-modules using generated plugin id i.e. `dev.all_things.reference.spring-boot-parent` in their `build.gradle.kts`.

```kotlin
plugins {

	// Other module specific plugins
	// ...

	// Spring Boot parent configuration for dependency management
	id("dev.all_things.reference.spring-boot-parent")
}
```

## Conclusion

A project can have multiple convention configurations. Multiple sub-modules in a project can also import one or more such configurations.

## Source Code

[GitHub Project](https://github.com/all-things-dev/kotlin-application-template)

## Keep in Touch

Please follow me on [Twitter](https://twitter.com/all_things_dev) where I regularly share my experiences with useful tools and frameworks.

## References

1. https://www.youtube.com/watch?v=So0j4RnoKkU
2. https://www.youtube.com/watch?v=iu_Tftpm6L8
3. https://www.youtube.com/watch?v=1hjle_eqEsw