Gradle多模块中用project(':xxx')声明依赖时会自动构建对应子模块,前提是该模块已在settings.gradle中include且构建命令作用于依赖方;坐标依赖则不会触发源码构建。

会,但只在特定条件下自动构建,且行为取决于依赖声明方式和构建触发范围
用 project(':xxx') 声明子模块依赖时,会自动构建
这是 Gradle 多项目构建的默认行为。当你在 build.gradle 里写 implementation project(':common'),Gradle 在执行当前模块的 compileJava 任务前,会自动触发 :common:compileJava(以及它依赖的 :common:processResources 等),前提是:
-
:common已在settings.gradle中通过include ':common'声明 - 当前构建命令作用于包含该依赖的模块,例如运行
./gradlew :app:build或./gradlew build(根项目) - 没有显式跳过依赖任务,比如加了
--no-build-cache不影响此行为,但加--dry-run或-x compileJava会绕过
用坐标依赖(如 implementation 'com.example:lib:1.0')时,不会自动构建源码
这种写法走的是 Maven 依赖解析流程,Gradle 只会去仓库找二进制(jar/aar),哪怕本地恰好有同坐标的源码工程,也不会自动拉进来编译。常见踩坑点:
- 误以为加了
includeBuild '../lib'后,所有implementation 'com.example:lib:1.0'都会走源码——其实必须确保../lib的build.gradle里group和version与依赖坐标完全一致,否则 fallback 到远程仓库 - IDEA 同步后显示依赖“存在”,但实际运行时类找不到,往往是因为
includeBuild没生效,或版本号不匹配导致用了远端旧包 -
includeBuild下的项目若本身有远端依赖(如spring-boot-starter-web),它仍会从仓库下载,不会递归把远端依赖也替换成本地源码
构建触发范围决定“自动构建”的深度
Gradle 不是无脑构建所有依赖,而是按需、按图执行。关键看命令作用域:
-
./gradlew :app:compileJava→ 只构建:app及其直接依赖的子项目(如:common),不构建:common的依赖(如:core)——除非:common的compileJava显式依赖:core:classes -
./gradlew :app:build→ 构建:app及其所有 transitive 子项目依赖(只要它们被project(...)声明),但不构建未被引用的兄弟模块(如:admin) -
./gradlew build(根目录)→ 构建所有include的子项目,无论是否被其他模块依赖
真正容易被忽略的是:子模块的构建是否执行,不取决于它有没有 build.gradle,而取决于它是否被某个正在执行的任务“需要”。一个没被任何 project(...) 引用的子模块,即使列在 settings.gradle 里,也不会在 :app:build 中被构建——除非你手动调它的任务,或者它被 build 生命周期钩住。


















