Gradle's multi-project build feature allows developers to manage multiple related projects in a single build, which is very useful for large applications and microservice architectures. Here's a detailed explanation of Gradle multi-project builds:
Multi-Project Build Structure
Basic Directory Structure
shellmy-project/ ├── settings.gradle ├── build.gradle ├── app/ │ ├── build.gradle │ └── src/ ├── library/ │ ├── build.gradle │ └── src/ └── common/ ├── build.gradle └── src/
settings.gradle Configuration
groovy// settings.gradle rootProject.name = 'my-project' // Include subprojects include 'app', 'library', 'common' // Include projects using relative paths include ':data:repository' project(':data:repository').projectDir = new File(rootDir, 'modules/data/repository') // Exclude project // include 'excluded-module'
Project Configuration
Root Project Configuration
groovy// build.gradle (root project) allprojects { group = 'com.example' version = '1.0.0' repositories { mavenCentral() } } subprojects { apply plugin: 'java' java { sourceCompatibility = JavaVersion.VERSION_17 } dependencies { implementation 'org.slf4j:slf4j-api:2.0.7' } }
Specific Project Configuration
groovy// app/build.gradle dependencies { implementation project(':library') implementation project(':common') testImplementation project(':common').sourceSets.test.output } // library/build.gradle dependencies { api project(':common') }
Project Dependencies
Inter-Project Dependencies
groovy// Using project() method dependencies { implementation project(':library') testImplementation project(':common').sourceSets.test.output // Using configuration implementation project(path: ':library', configuration: 'runtimeClasspath') }
Dependency Configuration
groovy// Define configuration in dependent project // library/build.gradle configurations { apiElements { canBeResolved = false canBeConsumed = true attributes { attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage, 'java-api')) } } } // Use in dependent project // app/build.gradle dependencies { implementation project(path: ':library', configuration: 'apiElements') }
Project Properties and Configuration
Project Properties
groovy// Define project properties ext { springBootVersion = '3.0.0' junitVersion = '5.9.0' } // Access in subprojects // app/build.gradle dependencies { implementation "org.springframework.boot:spring-boot-starter-web:${springBootVersion}" }
Conditional Configuration
groovy// Configure based on project name configure(subprojects.findAll { it.name.startsWith('web-') }) { apply plugin: 'war' } // Configure based on project properties subprojects { if (project.hasProperty('enableJacoco')) { apply plugin: 'jacoco' } }
Shared Configuration
Using Configuration Injection
groovy// build.gradle (root project) subprojects { // Configure all subprojects apply plugin: 'java' // Configure Java compilation tasks.withType(JavaCompile).configureEach { options.encoding = 'UTF-8' options.compilerArgs << '-Xlint:unchecked' } // Configure tests test { useJUnitPlatform() testLogging { events 'passed', 'skipped', 'failed' } } }
Using Convention Plugins
groovy// buildSrc/src/main/groovy/JavaLibraryPlugin.groovy class JavaLibraryPlugin implements Plugin<Project> { void apply(Project project) { project.with { apply plugin: 'java-library' java { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } dependencies { api platform('org.springframework.boot:spring-boot-dependencies:3.0.0') } } } } // Use in subprojects // library/build.gradle plugins { id 'java-library-convention' }
Build Tasks
Run Tasks Across All Projects
bash# Run clean task in all projects ./gradlew clean # Run test task in all projects ./gradlew test # Run tasks for specific project ./gradlew :app:build ./gradlew :library:test
Task Dependencies
groovy// app/build.gradle tasks.named('build') { dependsOn ':library:build', ':common:build' } // Root project build.gradle tasks.register('buildAll') { dependsOn subprojects.collect { "${it.path}:build" } }
Multi-Project Build Best Practices
1. Reasonable Project Division
groovy// Divide by functional modules include 'core', 'api', 'web', 'data', 'service' // Divide by layers include 'common', 'infrastructure', 'domain', 'application'
2. Shared Dependency Management
groovy// build.gradle (root project) ext { versions = [ springBoot: '3.0.0', junit: '5.9.0', mockito: '5.0.0' ] libs = [ springBootWeb: "org.springframework.boot:spring-boot-starter-web:${versions.springBoot}", junit: "org.junit.jupiter:junit-jupiter:${versions.junit}", mockito: "org.mockito:mockito-core:${versions.mockito}" ] } // Use in subprojects // app/build.gradle dependencies { implementation libs.springBootWeb testImplementation libs.junit testImplementation libs.mockito }
3. Use Version Catalog
groovy// gradle/libs.versions.toml [versions] spring-boot = "3.0.0" junit = "5.9.0" [libraries] spring-boot-web = { module = "org.springframework.boot:spring-boot-starter-web", version.ref = "spring-boot" } jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" } [plugins] java = { id = "java" } spring-boot = { id = "org.springframework.boot", version = "3.0.0" } // Use in subprojects // app/build.gradle plugins { id libs.plugins.java.get().pluginId } dependencies { implementation libs.spring.boot.web testImplementation libs.jupiter }
4. Avoid Circular Dependencies
groovy// Check for circular dependencies ./gradlew :app:dependencies --configuration runtimeClasspath // Use dependency analysis tools plugins { id 'com.github.dependency-license-report' version '2.5' }
Performance Optimization
Parallel Build
groovy// gradle.properties org.gradle.parallel=true org.gradle.caching=true org.gradle.configureondemand=true
Configuration Optimization
groovy// Use lazy configuration subprojects { tasks.register('customTask') { // Task is only created when needed } } // Avoid time-consuming operations in configuration phase subprojects { // Don't perform network requests or file I/O here }
Common Commands
bash# View project structure ./gradlew projects # View all tasks ./gradlew tasks # View tasks for specific project ./gradlew :app:tasks # View project dependencies ./gradlew :app:dependencies # Build all projects ./gradlew build # Build specific project ./gradlew :app:build # Clean all projects ./gradlew clean # Parallel build ./gradlew build --parallel