20. Maven 与 Gradle 构建工具深度实践

从生命周期到插件开发,从依赖冲突到多模块构建,深入 Maven 与 Gradle 的构建原理与生产实践

构建工具是 Java 工程的基石。从 Maven 的约定优于配置到 Gradle 的 DSL 编程式构建,两者各有胜负。理解它们的底层原理——生命周期、依赖传递、插件机制——是构建高效 CI/CD 流水线的必要条件。

1. Maven 核心架构

1.1 生命周期

Maven 有一套固定的三大生命周期,每个生命周期由多个阶段(Phase)组成:

clean 生命周期:
  pre-clean → clean → post-clean

default 生命周期(核心构建):
  validate → initialize → generate-sources → process-sources
  → generate-resources → process-resources → compile
  → process-classes → generate-test-sources → process-test-sources
  → generate-test-resources → process-test-resources
  → test-compile → process-test-classes → test
  → prepare-package → package → pre-integration-test
  → integration-test → post-integration-test
  → verify → install → deploy

site 生命周期:
  pre-site → site → post-site → site-deploy

常用命令与阶段对应

命令执行阶段说明
mvn compilecompile编译主源码
mvn testtest编译 + 运行测试
mvn packagepackage编译 + 测试 + 打包
mvn installinstall打包 + 安装到本地仓库
mvn deploydeploy安装 + 发布到远程仓库

1.2 POM 继承与 BOM

<!-- 父 POM: 统一管理版本和插件 -->
<project>
    <groupId>com.mycompany</groupId>
    <artifactId>parent-pom</artifactId>
    <version>1.0.0</version>
    <packaging>pom</packaging>

    <properties>
        <java.version>17</java.version>
        <spring-boot.version>3.2.0</spring-boot.version>
        <lombok.version>1.18.30</lombok.version>
    </properties>

    <!-- 依赖版本管理(子模块可引用但不强制继承) -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>  <!-- BOM 导入 -->
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <!-- 所有子模块强制继承的依赖 -->
    <dependencies>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
        </dependency>
    </dependencies>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <version>${spring-boot.version}</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>
<!-- 子模块 POM -->
<project>
    <parent>
        <groupId>com.mycompany</groupId>
        <artifactId>parent-pom</artifactId>
        <version>1.0.0</version>
    </parent>

    <artifactId>order-service</artifactId>

    <dependencies>
        <!-- 版本从 parent 的 dependencyManagement 继承,无需指定 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>
</project>

1.3 依赖传递与冲突解决

您的项目
  ├─ A → B(v1.0)
  └─ C → B(v2.0)

Maven 冲突解决: 路径最短优先 → 先声明优先
  B(v1.0) 路径: 您的项目 → A → B = 2 跳
  B(v2.0) 路径: 您的项目 → C → B = 2 跳
  路径相同 → 看 POM 中 A 和 C 谁先声明
# 查看依赖树,定位冲突
mvn dependency:tree -Dincludes=org.apache.commons:commons-lang3

# 查看依赖调解结果
mvn dependency:resolve

# 查看依赖分析报告
mvn dependency:analyze
<!-- 排除有漏洞的版本,显式指定安全版本 -->
<dependency>
    <groupId>com.some.library</groupId>
    <artifactId>problematic-lib</artifactId>
    <version>2.0</version>
    <exclusions>
        <exclusion>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.12.0</version>  <!-- 安全版本 -->
</dependency>

2. Maven 插件开发

2.1 自定义插件

/**
 * @goal greet
 * @phase compile
 */
@Mojo(name = "greet", defaultPhase = LifecyclePhase.COMPILE)
public class GreetingMojo extends AbstractMojo {

    @Parameter(defaultValue = "World", property = "greet.name")
    private String name;

    @Parameter(defaultValue = "${project}", readonly = true)
    private MavenProject project;

    @Override
    public void execute() throws MojoExecutionException {
        getLog().info("Hello, " + name + "!");
        getLog().info("Building: " + project.getArtifactId());
    }
}
<!-- 插件 POM -->
<packaging>maven-plugin</packaging>
<dependencies>
    <dependency>
        <groupId>org.apache.maven</groupId>
        <artifactId>maven-plugin-api</artifactId>
        <version>3.9.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.maven.plugin-tools</groupId>
        <artifactId>maven-plugin-annotations</artifactId>
        <version>3.9.0</version>
    </dependency>
</dependencies>
<!-- 使用自定义插件 -->
<plugin>
    <groupId>com.mycompany</groupId>
    <artifactId>greeting-maven-plugin</artifactId>
    <version>1.0</version>
    <executions>
        <execution>
            <goals><goal>greet</goal></goals>
        </execution>
    </executions>
    <configuration>
        <name>Developer</name>
    </configuration>
</plugin>

3. Gradle 核心概念

3.1 构建生命周期

初始化阶段: 确定参与构建的项目(settings.gradle)
       │
配置阶段: 执行所有 build.gradle,创建 Task 图
       │
执行阶段: 执行指定的 Task 及其依赖

3.2 Kotlin DSL vs Groovy DSL

// build.gradle.kts(推荐,类型安全)
plugins {
    java
    id("org.springframework.boot") version "3.2.0"
    id("io.spring.dependency-management") version "1.1.4"
}

java {
    sourceCompatibility = JavaVersion.VERSION_17
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("org.springframework.boot:spring-boot-starter-data-jpa")
    compileOnly("org.projectlombok:lombok")
    annotationProcessor("org.projectlombok:lombok")
    testImplementation("org.springframework.boot:spring-boot-starter-test")
}

tasks.test {
    useJUnitPlatform()
    testLogging {
        events("passed", "skipped", "failed")
    }
}

3.3 Gradle 依赖管理

dependencies {
    // 标准 scope 对照
    implementation("...")          // Maven compile(默认)
    compileOnly("...")             // Maven provided
    runtimeOnly("...")             // Maven runtime
    testImplementation("...")      // Maven test
    testCompileOnly("...")
    testRuntimeOnly("...")
    annotationProcessor("...")

    // 平台/ BOM 依赖
    implementation(platform("org.springframework.boot:spring-boot-dependencies:3.2.0"))

    // 排除传递依赖
    implementation("com.some:library:1.0") {
        exclude(group = "commons-logging")
    }

    // 严格版本
    implementation("com.google.guava:guava") {
        version {
            strictly("[32.0, 33.0[")
        }
    }
}

3.4 自定义 Task

// 自定义 Task 类型
open class GreetingTask : DefaultTask() {
    @Input
    var greeting: String = "Hello"

    @Input
    var recipient: String = "World"

    @OutputFile
    val outputFile: File = project.file("${project.buildDir}/greeting.txt")

    @TaskAction
    fun greet() {
        outputFile.writeText("$greeting, $recipient!")
    }
}

// 注册并使用
tasks.register<GreetingTask>("greet") {
    greeting = "Hi"
    recipient = "Gradle"
}

// 快捷脚本 Task
tasks.register<Copy>("copyConfig") {
    from("src/config")
    into("${project.buildDir}/config")
    include("*.properties")
}

4. 多模块构建

4.1 Maven 多模块

<!-- pom.xml (root) -->
<modules>
    <module>common-lib</module>
    <module>user-service</module>
    <module>order-service</module>
    <module>api-gateway</module>
</modules>
# 构建所有模块
mvn clean install

# 只构建特定模块及其依赖
mvn clean install -pl order-service -am
# -pl: projects list
# -am: also-make(构建依赖的模块)
# -amd: also-make-dependents(构建依赖该模块的所有模块)

4.2 Gradle 多模块

// settings.gradle.kts
rootProject.name = "my-platform"

include(
    "common-lib",
    "user-service",
    "order-service",
    "api-gateway"
)

// 可选:项目路径自定义
project(":user-service").projectDir = file("services/user")
// 子模块 build.gradle.kts
plugins {
    `java-library`  // 提供 api() 依赖声明
}

dependencies {
    api(project(":common-lib"))     // 传递暴露
    implementation(project(":internal-lib"))  // 不传递
}

Gradle 构建优化

// gradle.properties
org.gradle.parallel=true          // 并行构建模块
org.gradle.caching=true           // 构建缓存
org.gradle.configureondemand=true // 按需配置
org.gradle.daemon=true            // 守护进程

5. 构建安全与扫描

5.1 依赖漏洞扫描

<!-- Maven: OWASP Dependency-Check -->
<plugin>
    <groupId>org.owasp</groupId>
    <artifactId>dependency-check-maven</artifactId>
    <version>8.4.0</version>
    <configuration>
        <failBuildOnCVSS>7</failBuildOnCVSS>
    </configuration>
    <executions>
        <execution>
            <goals><goal>check</goal></goals>
        </execution>
    </executions>
</plugin>
// Gradle: OWASP Dependency-Check
plugins {
    id("org.owasp.dependencycheck") version "8.4.0"
}

dependencyCheck {
    analyzers {
        assemblyEnabled = false
    }
    failBuildOnCVSS = 7.0f
}

5.2 License 合规检查

<!-- Maven License Plugin -->
<plugin>
    <groupId>com.mycila</groupId>
    <artifactId>license-maven-plugin</artifactId>
    <version>4.2</version>
    <configuration>
        <header>LICENSE-HEADER.txt</header>
        <includes>
            <include>src/main/java/**/*.java</include>
        </includes>
    </configuration>
</plugin>

6. Maven vs Gradle 选型对比

维度MavenGradle
配置语言XMLGroovy / Kotlin
学习曲线低(约定优于配置)中高(灵活但复杂)
构建速度高(增量构建 + 构建缓存)
灵活性高(完整的编程能力)
IDE 支持极好极好
生态成熟度极高
多语言构建强(原生 C/C++、Android)
脚本调试困难容易

选型建议

  • 纯 Java/Kotlin 后端 Spring Boot 项目:两者皆可,团队熟悉哪个用哪个
  • Android 项目:Gradle 唯一选择
  • 需要复杂构建逻辑(条件编译、动态配置):Gradle 更灵活
  • 需要极速构建:Gradle + 构建缓存

延伸阅读

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「java-enterprise」更多文章

  1. 限流算法深度解析:令牌桶、漏桶与滑动窗口计数
  2. Java 代码质量:SonarQube、Checkstyle 与 SpotBugs 工程化实践
  3. Spring IoC 容器与依赖注入原理深度剖析