复合构建适用于跨仓库、未发布代码的实时联调,核心是让独立项目像子模块一样可调试、可断点;仅当项目属不同Git仓库且暂未发布时才需使用,同仓库应优先采用多项目构建。

在大型复杂企业架构中,用 Gradle 的 Composite Builds(复合构建)把独立项目当成本地模块联调,核心不是“加个 includeBuild 就完事”,而是要让跨仓库、跨团队、尚未发布到 Maven 仓库的代码,像同一单体项目里的子模块一样实时生效、可调试、可断点。它解决的是“依赖未发布却要验证集成”的真实痛点,尤其适用于微服务拆分后各服务并行开发、中间件 SDK 迭代、或基础平台组件灰度验证等场景。
明确复合构建的适用边界
Composite Builds 不是用来替代多项目构建(multi-project build)的。如果所有模块本就属于同一个 Git 仓库、统一维护,优先用 settings.gradle.kts 中 include + project(':xxx') 依赖——更轻量、无额外构建生命周期开销、IDE 支持更原生。只有当下列情况同时满足时,才真正需要复合构建:
- 被联调的项目是独立 Git 仓库(比如 auth-service、common-utils-sdk),且暂未发布 SNAPSHOT 到 Nexus 或 Artifactory
- 你希望在主应用(my-app)里直接修改被联调项目的源码,并立即看到效果,无需手动 publish 到本地 Maven 仓库再 refresh
- 被联调项目本身有完整构建逻辑(如自定义插件、特殊 task、复杂的 dependency constraints),不能简单当作 jar 依赖引入
标准接入流程:三步落地
以主项目 my-app 联调独立仓库 common-utils 为例:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
在 my-app 的 settings.gradle.kts 中声明包含:
includeBuild("../common-utils")
注意路径是相对于my-app/settings.gradle.kts的相对路径,且common-utils目录下必须存在settings.gradle.kts(哪怕为空)——这是 Gradle 识别它为独立构建的关键信号。 -
在 my-app 的 build.gradle.kts 中按插件 ID 应用:
若common-utils发布了一个插件org.example.utils,则直接写:plugins { id("org.example.utils") version "1.2.0-SNAPSHOT" }
Gradle 会自动从 included build 中解析该插件,无需配置 pluginManagement repositories。 -
跨项目依赖写法保持不变:
在my-app的build.gradle.kts里,仍用implementation(project(":common-utils"))(前提是common-utils的根 project 名为common-utils);
它不会去 Maven 仓库找,而是直接复用 included build 编译产出的 classes 和 resources。
关键细节与避坑点
复合构建看似简单,但以下细节决定联调是否顺滑:
立即学习“Java免费学习笔记(深入)”;
-
版本号不强制对齐:主项目引用
version "1.2.0-SNAPSHOT",而common-utils的version = "1.3.0-SNAPSHOT"完全没问题——Gradle 只认 included build 实际构建出的产物,不走版本解析。 -
依赖替换需显式声明:若
common-utils里用了slf4j-api:2.0.0,而my-app希望强制使用2.0.1,不能只在主项目写constraints,必须在my-app/settings.gradle.kts中补充:dependencyResolutionManagement { resolutionStrategy { force("org.slf4j:slf4j-api:2.0.1") } } -
IDE 同步要主动触发:IntelliJ 默认不会自动识别 included build 的变更。修改
common-utils后,需右键my-app→ Reload project,或手动执行./gradlew --refresh-dependencies。 -
调试支持天然可用:在
common-utils的任意 Java/Kotlin 文件中打断点,运行my-app的测试或 main 方法,IDE 会直接跳入源码——因为 classpath 指向的是编译输出目录,而非 jar 包。
对比多项目构建:何时选谁?
别为了“高大上”硬套复合构建。实际决策看协作粒度:
- 同团队、同仓库、每日合并 → 用 multi-project(include + project dependency),构建快、配置集中、CI 友好
- 跨团队、不同 Git 仓库、接口契约已定但实现未发布 → 用 composite build,隔离风险、避免污染主仓库、便于灰度验证
- 想彻底解耦、未来可能开源或供外部使用 → 把
common-utils发布为正式版 artifact,主项目走mavenCentral()或私仓依赖,最稳定

















