Gradle 最佳实践

FreeGuideOnline 最新 2026-07-14

my-project/ ├── build.gradle.kts (根项目配置) ├── settings.gradle.kts ├── app/ (主业务模块) │ └── build.gradle.kts ├── core/ (核心工具、领域模型) │ └── build.gradle.kts └── infrastructure/ (数据库、外部服务适配器) └── build.gradle.kts


**关键设置**:
- **`settings.gradle.kts`** 中声明子模块:
  ```kotlin
  rootProject.name = "my-project"
  include("app", "core", "infrastructure")
  • 子模块间通过 implementation(project(":core")) 声明依赖。
  • 大项目推荐按功能或层级划分模块,避免深层嵌套,一般不超过 3-4 层。

3. 依赖管理:集中版本与严格冲突解决

混乱的版本声明是运行时错误的温床。集中管理可以提升可维护性。

最佳实践

  • 使用版本目录(Version Catalog):在 gradle/libs.versions.toml 中统一定义所有库版本。

    [versions]
    spring-boot = "3.3.4"
    kotlin = "2.0.20"
    
    [libraries]
    spring-boot-starter-web = { module = "org.springframework.boot:spring-boot-starter-web", version.ref = "spring-boot" }
    kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
    
    [plugins]
    spring-boot = { id = "org.springframework.boot", version.ref = "spring-boot" }
    

    然后在 build.gradle.kts 中引用:

    dependencies {
        implementation(libs.spring.boot.starter.web)
    }
    
  • 启用依赖锁定:生成 gradle.lockfile 以确保二级依赖的版本不变。

    dependencyLocking {
        lockAllConfigurations()
    }
    

    使用 ./gradlew dependencies --write-locks 生成或更新锁定文件。

  • 使用严格版本冲突解决策略

    configurations.all {
        resolutionStrategy {
            // 遇到版本冲突直接失败,迫使开发者显式解决
            failOnVersionConflict()
            // 或者强制特定版本
            force("com.squareup.okhttp3:okhttp:4.12.0")
        }
    }
    

4. 优化构建速度:配置缓存与并行构建

Gradle 提供了强大的增量构建能力,但需要正确开启。

必须开启的特性

  • 配置缓存(Configuration Cache):缓存 “构建配置” 阶段的结果,显著缩短流水线。在项目根目录 gradle.properties 中添加:

    org.gradle.configuration-cache=true
    org.gradle.unsafe.configuration-cache.max-problems=0
    
  • 构建缓存(Build Cache):共享和复用任务输出。本地开启:

    org.gradle.caching=true
    

    在 CI 环境推荐设置 远程缓存节点(如 Gradle Enterprise 或兼容的 HTTP 后端)。

  • 并行执行:开启多模块并行构建:

    org.gradle.parallel=true
    
  • 增加 JVM 堆内存

    org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError
    
  • 避免动态任务创建与无意义配置:尽量使用懒创建(如 tasks.register())而非 tasks.create()


5. 使用 Kotlin DSL 编写构建脚本

为何转向 Kotlin DSL

  • 静态类型,IDE 自动补全、跳转、重构支持极佳。
  • 脚本和项目代码使用同一种语言,降低上下文切换成本。
  • 编译期错误检查,避免 Groovy 脚本运行时的意外错误。

迁移小贴士

  • build.gradle 重命名为 build.gradle.kts
  • 函数调用需要使用括号,赋值用 = 替代 Groovy 的 = 混淆。
  • 示例对比:
    // Groovy
    task copyFiles(type: Copy) {
        from 'src'
        into 'dest'
    }
    // Kotlin DSL
    tasks.register<Copy>("copyFiles") {
        from("src")
        into("dest")
    }
    

6. 任务编写原则:幂等、增量与缓存

良好的任务设计让构建可预测且快速。

  • 显式声明输入与输出:使用 @Input, @OutputDirectory, @InputFiles 等注解,以便 Gradle 启用增量构建。
    abstract class GenerateReport : DefaultTask() {
        @get:InputFiles
        abstract val dataFiles: ConfigurableFileCollection
    
        @get:OutputFile
        abstract val reportFile: RegularFileProperty
    
        @TaskAction
        fun execute() {
            // 仅当输入更改时才运行
        }
    }
    
  • 避免在任务中执行副作用:所有副作用应限于 @Output 目录或文件,不要修改项目源目录。
  • 清理构建:自定义任务应正确贡献到 clean 任务,通常通过将输出放在 build 目录下自动完成。

7. 依赖配置最佳选择:api vs implementation

在多模块或库项目中,暴露不必要的传递依赖会造成耦合和编译慢。

  • implementation:依赖只在模块内部可用,编译路径不会传染给下游模块。首选这一配置
  • api:依赖会传递给所有依赖该模块的项目。仅在公共 API 返回类型或参数中使用时才声明为 api
  • compileOnlyruntimeOnly 分别用于编译时可见但运行时由容器提供,或编译时不需要但运行时必需的库。

示例

dependencies {
    // 内部实现细节,不泄露
    implementation("com.google.guava:guava:33.3.0-jre")
    // 公开 API 中返回了某类型,所以必须 api
    api("org.apache.commons:commons-lang3:3.14.0")
    compileOnly("org.projectlombok:lombok:1.18.34") // 注解处理器由编译器处理
    annotationProcessor("org.projectlombok:lombok:1.18.34")
}

8. 编写可复用的插件与约定(Convention Plugins)

在多模块项目中,许多配置是重复的(如编译器设置、测试框架)。使用约定插件避免重复代码。

步骤:

  1. buildSrc/src/main/kotlin/my-java-convention.gradle.kts 中定义通用配置:
    plugins {
        java
    }
    java {
        toolchain {
            languageVersion = JavaLanguageVersion.of(21)
        }
    }
    testing {
        suites.named("test") { useJUnitJupiter() }
    }
    
  2. 在子模块中应用:
    plugins {
        id("my-java-convention")
    }
    
  3. 更成熟的方案是使用包含插件(Included Builds)或独立发布插件,但 buildSrc 对于中小型项目已足够。

9. 健康检查:构建扫描与依赖报告

构建扫描(Build Scan):无需本地安装,运行 ./gradlew build --scan,在输出链接中查看性能分析、任务依赖图、配置时间等。诊断速度问题时首先做一次扫描。

依赖分析

  • ./gradlew :app:dependencies --configuration runtimeClasspath 查看传递依赖树。
  • 使用插件 com.autonomousapps.dependency-analysis 自动发现未使用的依赖和错误配置。
    plugins {
       id("com.autonomousapps.dependency-analysis") version "1.32.0"
    }
    
    运行 ./gradlew buildHealth 可获得详细报告。

版本兼容性检查:使用 gradle-versions-plugin 检测可用的依赖更新和 Gradle 版本升级。

plugins {
    id("com.github.ben-manes.versions") version "0.51.0"
}
// 任务: ./gradlew dependencyUpdates -Drevision=release

10. 持续集成优化

  • 仅构建和测试变更的模块:利用 Gradle 的依赖图,结合 --changed 参数(需要 git):
    ./gradlew build --changed