Gradle:Java项目的现代构建利器
简介Gradle 是 Java 生态里常见的构建工具。它负责把一个项目从源码变成可运行、可测试、可发布的构建产物。一个 Java 项目通常会涉及这些事情下载依赖 编译源码 处理资源文件 运行测试 打包 jar / bootJar 发布到 Maven 仓库 组织多模块构建Gradle 的核心特点是用插件提供构建能力 用任务组织构建动作 用 DSL 描述构建配置 用 Wrapper 固定项目 Gradle 版本一句话概括Gradle 是一个灵活、可扩展、支持增量构建和多模块工程的现代构建工具。Gradle 解决什么问题没有构建工具时Java 项目需要手动处理很多事情手动下载 jar 手动配置 classpath 手动执行 javac 手动运行测试 手动打包 jar 手动处理多模块编译顺序项目小的时候还能接受项目变大后很容易失控。Gradle 的做法是标准目录约定 声明依赖 应用插件 执行任务 自动计算任务顺序 复用构建缓存比如执行./gradlew buildGradle 会自动完成读取 settings.gradle.kts 读取 build.gradle.kts 解析插件和依赖 编译 main 代码 编译 test 代码 运行测试 打包产物 生成构建结果Gradle 和 Maven 的关系Gradle 和 Maven 都是构建工具都能使用 Maven 仓库里的依赖。区别主要在写法和构建模型上。对比项MavenGradle配置文件pom.xmlbuild.gradle/build.gradle.kts配置风格XMLGroovy DSL / Kotlin DSL生命周期固定生命周期任务图 DAG插件机制插件绑定生命周期阶段插件添加任务和扩展灵活性约定强写法稳定可编程能力更强多模块父 POM modulessettings include project dependency依赖仓库Maven 仓库Maven 仓库、Ivy 仓库等Maven 更像按照固定生命周期跑标准流程。Gradle 更像根据任务依赖关系生成任务图再按任务图执行。Gradle Wrapper实际项目里通常不直接使用本机的gradle命令而是使用 Gradle Wrapper。./gradlew buildWindows 下是gradlew.bat buildWrapper 的作用是让项目固定使用某个 Gradle 版本。常见文件结构gradle-demo/ ├── gradlew ├── gradlew.bat ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── settings.gradle.kts └── build.gradle.ktsgradle-wrapper.properties里会指定 Gradle 发行包地址distributionUrlhttps\://services.gradle.org/distributions/gradle-9.6.1-bin.zip这样无论本机是否安装 Gradle只要有 JDK就可以通过./gradlew执行构建。生成 Wrappergradle wrapper --gradle-version 9.6.1升级 Wrapper./gradlew wrapper --gradle-version 9.6.1项目里的 Wrapper 文件应该提交到 Git。这样 CI、开发机、构建服务器都能使用同一个 Gradle 版本。Gradle 运行 JDK 和项目编译 JDKGradle 自己运行需要 JVM。当前 Gradle 9.x 要求运行 Gradle 的 JVM 至少是 Java 17。但项目代码编译使用哪个 JDK可以通过 Java Toolchain 单独指定。java { toolchain { languageVersion JavaLanguageVersion.of(21) } }这表示Gradle 自己可以运行在 Java 17 项目源码使用 Java 21 工具链编译Toolchain 的好处是构建更稳定。不同机器上的JAVA_HOME不一致时Gradle 仍然可以选择符合要求的 JDK 来编译项目。Gradle 项目目录标准 Java 项目目录和 Maven 很接近。gradle-java-demo/ ├── settings.gradle.kts ├── build.gradle.kts ├── gradle.properties ├── gradlew ├── gradlew.bat ├── gradle/ │ └── wrapper/ └── src/ ├── main/ │ ├── java/ │ └── resources/ └── test/ ├── java/ └── resources/几个核心文件文件作用settings.gradle.kts设置根项目名称、声明子模块、配置插件仓库build.gradle.kts当前项目或模块的构建脚本gradle.propertiesGradle 参数、项目属性gradlewmacOS / Linux Wrapper 命令gradlew.batWindows Wrapper 命令gradle-wrapper.propertiesWrapper 使用的 Gradle 版本settings.gradle.kts单模块项目pluginManagement { repositories { gradlePluginPortal() mavenCentral() } } dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { mavenCentral() } } rootProject.name gradle-java-demo多模块项目rootProject.name mall-system include(mall-common) include(mall-domain) include(mall-service) include(mall-web)settings.gradle.kts是 Gradle 初始化阶段会读取的文件。它决定这次构建包含哪些项目。build.gradle.kts 基础模板下面是一个普通 Java 应用的build.gradle.kts。plugins { java application } group com.example version 1.0.0-SNAPSHOT java { toolchain { languageVersion JavaLanguageVersion.of(21) } } repositories { mavenCentral() } dependencies { implementation(org.slf4j:slf4j-api:2.0.18) runtimeOnly(ch.qos.logback:logback-classic:1.5.15) testImplementation(org.junit.jupiter:junit-jupiter:5.11.4) } application { mainClass.set(com.example.demo.MainApplication) } tasks.test { useJUnitPlatform() }这个文件做了几件事配置作用plugins应用 Java 和 Application 插件group项目组织名version项目版本java.toolchain指定 Java 编译工具链repositories依赖从哪里下载dependencies项目依赖application.mainClass可运行应用入口类tasks.test配置测试任务Groovy DSL 和 Kotlin DSLGradle 支持两种常见 DSL文件DSLbuild.gradleGroovy DSLbuild.gradle.ktsKotlin DSLGroovy DSLplugins { id java } dependencies { implementation org.springframework.boot:spring-boot-starter-web }Kotlin DSLplugins { java } dependencies { implementation(org.springframework.boot:spring-boot-starter-web) }Kotlin DSL 的类型提示和 IDE 补全通常更好新项目可以优先使用build.gradle.kts。老项目里遇到build.gradle也很正常。常用命令日常命令通常使用 Wrapper。./gradlew tasks查看所有任务。./gradlew clean清理build目录。./gradlew compileJava编译 main 源码。./gradlew test运行测试。./gradlew build完整构建通常包含编译、测试、打包。./gradlew jar打普通 jar。./gradlew dependencies查看依赖树。./gradlew dependencyInsight --dependency logback-classic查看某个依赖为什么被引入。./gradlew build -x test构建时跳过测试。构建生命周期Gradle 构建有三个阶段阶段做什么初始化读取settings.gradle.kts确定参与构建的项目配置读取各模块build.gradle.kts配置 Project 和 Task执行根据任务图执行被请求的任务执行./gradlew buildGradle 不会简单地从上到下跑脚本。它会先生成任务图再执行任务图里的任务。比如build可能依赖compileJava processResources classes compileTestJava test jar assemble check插件会向项目添加任务任务之间可以声明依赖关系。Task 是 Gradle 的执行单元查看任务./gradlew tasks自定义一个简单任务tasks.register(hello) { group demo description 打印一条 Gradle 消息 doLast { println(Hello Gradle) } }执行./gradlew hello任务依赖tasks.register(packageInfo) { dependsOn(test) doLast { println(测试通过后生成打包信息) } }dependsOn(test)表示执行packageInfo前先执行test。Plugin 是能力入口Gradle 很多能力都来自插件。比如 Java 插件plugins { java }它会添加compileJava processResources classes jar compileTestJava test buildApplication 插件plugins { application }它会添加run installDist distZip distTarSpring Boot 插件plugins { id(org.springframework.boot) version 3.5.0 id(io.spring.dependency-management) version 1.1.7 java }它会添加bootRun bootJar bootBuildImage简单理解插件负责把某类构建能力接入项目。 任务负责真正执行构建动作。依赖配置怎么选Gradle 依赖不是只有一个compile。常见配置如下配置说明implementation编译和运行需要但不暴露给依赖当前模块的其他模块api编译和运行需要并暴露给依赖当前模块的其他模块compileOnly编译需要运行时由环境提供runtimeOnly编译不需要运行时需要testImplementation测试编译和运行需要testRuntimeOnly测试运行时需要annotationProcessor注解处理器比如 Lombok、MapStruct示例dependencies { implementation(org.springframework.boot:spring-boot-starter-web) compileOnly(org.projectlombok:lombok) annotationProcessor(org.projectlombok:lombok) runtimeOnly(com.mysql:mysql-connector-j) testImplementation(org.springframework.boot:spring-boot-starter-test) testRuntimeOnly(org.junit.platform:junit-platform-launcher) }implementation和api的区别在多模块里很重要。假设mall-web - mall-service - mall-domain如果mall-service的公开方法签名里暴露了mall-domain类型就可以用api(project(:mall-domain))。如果只是内部使用就用implementation(project(:mall-domain))。使用api需要应用java-library插件plugins { java-library }依赖排除和版本冲突排除传递依赖dependencies { implementation(org.springframework.boot:spring-boot-starter-web) { exclude(group org.springframework.boot, module spring-boot-starter-tomcat) } }查看依赖来源./gradlew dependencyInsight --dependency spring-boot-starter-tomcat刷新依赖缓存./gradlew --refresh-dependencies buildGradle 会做版本冲突解析通常选择较高版本。Spring Boot 项目一般交给 Boot 的 BOM 和依赖管理控制版本业务模块少手写三方依赖版本。Version Catalog集中管理依赖版本多模块项目里依赖版本散落在各个build.gradle.kts中会很难维护。Gradle 推荐使用 Version Catalog。文件位置gradle/libs.versions.toml示例[versions] spring-boot 3.5.0 junit-jupiter 5.11.4 mapstruct 1.6.3 [libraries] junit-jupiter { module org.junit.jupiter:junit-jupiter, version.ref junit-jupiter } mapstruct { module org.mapstruct:mapstruct, version.ref mapstruct } mapstruct-processor { module org.mapstruct:mapstruct-processor, version.ref mapstruct } [plugins] spring-boot { id org.springframework.boot, version.ref spring-boot }build.gradle.kts中使用plugins { alias(libs.plugins.spring.boot) java } dependencies { implementation(libs.mapstruct) annotationProcessor(libs.mapstruct.processor) testImplementation(libs.junit.jupiter) }这样版本集中在一个文件里多模块升级更方便。Spring Boot Gradle 项目一个常见 Spring Boot 单模块配置如下plugins { java id(org.springframework.boot) version 3.5.0 id(io.spring.dependency-management) version 1.1.7 } group com.example version 1.0.0 java { toolchain { languageVersion JavaLanguageVersion.of(21) } } repositories { mavenCentral() } dependencies { implementation(org.springframework.boot:spring-boot-starter-web) implementation(org.springframework.boot:spring-boot-starter-validation) runtimeOnly(com.mysql:mysql-connector-j) testImplementation(org.springframework.boot:spring-boot-starter-test) testRuntimeOnly(org.junit.platform:junit-platform-launcher) } tasks.test { useJUnitPlatform() }开发阶段运行./gradlew bootRun打生产包./gradlew clean bootJar产物一般在build/libs/运行java -jar build/libs/demo-1.0.0.jarbootJar会生成 Spring Boot 可执行 jar。普通jar任务生成的是普通 jar通常不包含 Spring Boot 启动所需的嵌套依赖结构。bootRun、bootJar、jar 的区别任务作用常见命令bootRun直接从源码和 runtime classpath 启动 Spring Boot 应用./gradlew bootRunbootJar打 Spring Boot 可执行 jar./gradlew bootJarjar打普通 jar./gradlew jarbuild执行完整构建通常会包含测试和打包./gradlew build开发阶段常用./gradlew bootRunCI 或发版阶段常用./gradlew clean build或者只打 Spring Boot 可执行包./gradlew clean bootJar多模块项目一个典型多模块结构mall-system/ ├── settings.gradle.kts ├── build.gradle.kts ├── mall-common/ │ └── build.gradle.kts ├── mall-domain/ │ └── build.gradle.kts ├── mall-service/ │ └── build.gradle.kts └── mall-web/ └── build.gradle.ktssettings.gradle.ktsrootProject.name mall-system include(mall-common) include(mall-domain) include(mall-service) include(mall-web)根build.gradle.ktsplugins { java id(org.springframework.boot) version 3.5.0 apply false id(io.spring.dependency-management) version 1.1.7 apply false } allprojects { group com.example version 1.0.0 repositories { mavenCentral() } } subprojects { apply(plugin java) java { toolchain { languageVersion JavaLanguageVersion.of(21) } } tasks.withTypeTest().configureEach { useJUnitPlatform() } }mall-service/build.gradle.ktsplugins { java-library } dependencies { api(project(:mall-domain)) implementation(project(:mall-common)) }mall-web/build.gradle.ktsplugins { id(org.springframework.boot) id(io.spring.dependency-management) } dependencies { implementation(project(:mall-service)) implementation(org.springframework.boot:spring-boot-starter-web) testImplementation(org.springframework.boot:spring-boot-starter-test) }构建整个项目./gradlew clean build只构建某个模块./gradlew :mall-web:build只运行 Web 模块./gradlew :mall-web:bootRungradle.propertiesgradle.properties常用于放 Gradle 构建参数和项目属性。org.gradle.jvmargs-Xmx2g -Dfile.encodingUTF-8 org.gradle.paralleltrue org.gradle.cachingtrue projectVersion1.0.0在build.gradle.kts中读取version providers.gradleProperty(projectVersion).get()常见配置配置作用org.gradle.jvmargsGradle Daemon JVM 参数org.gradle.parallel多项目并行构建org.gradle.caching启用构建缓存自定义属性项目版本、仓库地址等账号、Token、私服密码不适合直接提交到项目仓库。这类信息可以放到用户目录的~/.gradle/gradle.properties或者由 CI 环境变量注入。发布到 Maven 仓库Gradle 可以用maven-publish插件发布构建产物。plugins { java-library maven-publish } group com.example version 1.0.0 publishing { publications { createMavenPublication(mavenJava) { from(components[java]) } } repositories { maven { name localRepo url uri(layout.buildDirectory.dir(repo)) } } }发布到本地 Maven 仓库./gradlew publishToMavenLocal发布到配置的仓库./gradlew publish公共库、内部 SDK、多模块基础组件经常会用到发布能力。自定义任务示例生成构建信息下面定义一个任务生成build/generated/build-info.txt。abstract class GenerateBuildInfoTask : DefaultTask() { get:OutputFile abstract val outputFile: RegularFileProperty TaskAction fun generate() { outputFile.get().asFile.writeText( name${project.name} version${project.version} time${java.time.Instant.now()} .trimIndent() ) } } tasks.registerGenerateBuildInfoTask(generateBuildInfo) { outputFile.set(layout.buildDirectory.file(generated/build-info.txt)) }执行./gradlew generateBuildInfoGradle 任务可以声明输入和输出。输入输出声明清楚后Gradle 才能更好地做增量构建和缓存。IDEA 里 Gradle 面板怎么理解IDEA 的 Gradle 面板通常会展示Tasks Dependencies PluginsTasks是可以执行的任务。比如build clean test bootRun bootJar dependencies双击任务本质上类似执行./gradlew bootRunPlugins是当前项目应用的插件。插件会贡献任务和配置项。比如 Spring Boot 插件贡献bootRun、bootJarJava 插件贡献compileJava、test、jar。所以 IDEA 里真正执行的是任务不是插件本身。常见问题gradle 和 gradlew 用哪个项目内优先使用./gradlew build它会使用项目指定的 Gradle 版本。本机gradle更适合初始化 Wrapper 或做临时实验。build 和 bootJar 有什么区别bootJar只负责生成 Spring Boot 可执行 jar。build是生命周期任务会执行检查、测试、打包等一组任务。Spring Boot 项目里build通常也会触发bootJar。为什么依赖下载很慢常见原因是网络、仓库源、公司代理。可以在settings.gradle.kts或企业统一 Gradle 配置里设置仓库。repositories { mavenCentral() maven(https://maven.aliyun.com/repository/public) }企业项目更推荐使用内部 Nexus、Artifactory 这类私服。为什么修改代码后没有重新编译全部内容Gradle 支持增量构建。如果输入和输出没有变化对应任务可能显示UP-TO-DATE。 Task :compileJava UP-TO-DATE这表示 Gradle 判断该任务不需要重新执行。implementation 和 api 怎么选默认优先用implementation。只有当前模块的公开 API 暴露了某个依赖类型时才考虑api。这样可以减少无关依赖传递提高编译隔离效果。Spring Boot 项目能不能只执行 jar可以执行jar但它生成的是普通 jar。Spring Boot 应用通常使用./gradlew bootJarbootJar生成的 jar 才包含 Spring Boot 可执行应用所需的启动结构。实践建议场景建议项目构建使用./gradlew新项目 DSL优先使用 Kotlin DSLJava 版本使用java.toolchain固定Spring Boot 运行开发阶段用bootRunSpring Boot 打包发版阶段用clean bootJar或clean build多模块依赖默认implementation必要时api依赖版本多模块使用 Version Catalog依赖排查使用dependencies和dependencyInsight构建性能开启缓存、并行构建避免低质量自定义任务敏感配置放到用户级 Gradle 配置或 CI 环境变量小结Gradle 的核心不是某个单独命令而是一套任务驱动的构建模型。Wrapper 负责固定 Gradle 版本settings.gradle.kts决定构建包含哪些项目build.gradle.kts描述插件、依赖和任务插件贡献具体构建能力任务组成最终的执行图。普通 Java 项目关注java、application、test、jar。Spring Boot 项目还要关注bootRun和bootJar。多模块项目则要进一步关注settings.gradle.kts、模块依赖、api/implementation、Version Catalog 和统一构建配置。把这些概念串起来后Gradle 就不只是“能打包”的工具而是可以支撑复杂工程构建、依赖治理和持续交付的构建系统。