1. 多模块项目结构设计

在现代 Java/Android 工程中,随着业务规模和团队人数的增长,单模块项目逐渐暴露出编译缓慢、职责耦合、重复代码等痛点。Gradle 多模块构建通过将一个大型工程拆分为多个逻辑独立、相互协作的子项目,实现关注点分离、编译加速和复用提升。本章从结构设计出发,讲解模块划分原则、目录约定以及根项目与子项目的协作关系,为后续构建优化打下基础。

1.1 模块划分原则

合理的模块划分是多模块构建成功的基石。以下是经过大量项目验证的四个核心原则:

原则 说明 反例
单一职责 每个模块只关注一个业务/技术领域,如数据访问、业务逻辑、UI 展示等 一个模块同时包含数据层和网络层,导致改动相互影响
可复用性 通用工具、公共模型、基础库应抽取为独立模块,供其他模块依赖 在每个业务模块都复制一份相同的工具类
依赖方向稳定 上层业务模块依赖下层基础模块,不允许下层引用上层接口 数据层模块直接依赖了 UI 层的 View 类
可测试性 模块可脱离其他模块单独编译和运行测试 模块强依赖外部容器或数据库,无法进行单元测试
实战建议:在项目初期建立模块清单,用表格罗列每个模块的名称、职责、对外暴露接口和依赖关系,并在代码评审中持续维护。

1.2 目录约定

Gradle 通过settings.gradle声明参与构建的子项目,子项目的目录结构与模块名称通常一一对应。推荐采用以下约定:

root-project/
├── settings.gradle                    # 声明子项目
├── build.gradle                       # 根项目配置(可选)
├── gradle/
│   ├── wrapper/
│   └── libs.versions.toml             # 版本目录
├── common/                            # 公共模块
│   ├── build.gradle
│   └── src/
├── data/                              # 数据层模块
│   ├── build.gradle
│   └── src/
├── core/                              # 核心业务模块
│   ├── build.gradle
│   └── src/
└── web/                               # Web 展示模块
    ├── build.gradle
    └── src/

子模块名称与目录名一致,且采用小写 + 连字符(如user-service)便于阅读和命令行操作。

1.3 根项目与子项目的关系

根项目(Root Project)是整个多模块构建的入口,负责声明子项目、提供公共插件和依赖版本,一般不包含业务代码。子项目(Subproject)是实际构建单元,每个子项目有独立的build.gradle,也可通过根项目的allprojects或subprojects代码块继承公共配置。

核心配置示例:

settings.gradle

rootProject.name = 'my-multiproject'
include(':common', ':data', ':core', ':web')

根项目 build.gradle

plugins {
    id 'java-library'
}

// 给所有子项目统一配置
subprojects {
    apply plugin: 'java-library'
    group = 'com.example'
    version = '1.0.0'
    repositories {
        mavenCentral()
    }
    dependencies {
        testImplementation 'junit:junit:4.13.2'
    }
}

子项目 core/build.gradle

dependencies {
    implementation project(':common')   // 依赖同一工程下的common模块
    implementation 'com.google.guava:guava:31.1-jre'
}

依赖引用使用project(':模块名')语法,Gradle 会自动处理模块间编译顺序和增量编译。

关键概念:根项目的build.gradle默认只配置自身,若要对所有子项目生效,需使用subprojects { };使用allprojects { }则同时包含根项目和子项目,通常用于统一仓库和全局插件。

1.4 多模块项目结构示意图

下图展示了一个典型三层次多模块结构,包含公共模块、核心业务模块和展示模块,并标注了依赖方向。

多模块项目结构依赖关系图 根项目 (Root) :common :data :core :web :utils 依赖方向说明: - 根项目只负责声明和公共配置,不包含业务代码。 - 所有子项目均可依赖 :common(通用工具/模型),但 :common 不能反向依赖任何子项目。 - :web 可同时依赖 :core 和 :data,形成清晰的层级。

1.5 常见错误与调试

  • 子项目未被识别:未在 settings.gradle 中 include 对应模块,导致 Gradle 提示“Project with path ‘:xxx’ not found”。
  • 循环依赖:模块 A 依赖 B,B 又依赖 A,Gradle 在编译时抛出 Circular dependency 错误。解决方法是提取公共部分到独立的 :common 模块。
  • 版本不一致:不同子项目使用了不同版本的三方库,导致运行时冲突。应统一在根项目或版本目录中管理依赖版本。
调试命令:执行 gradle projects 可查看当前工程包含的所有子项目及其分组结构。若子项目列表与预期不符,优先检查 settings.gradle 的正确性。

1.6 性能与稳定性考量

关注点 优化手段
增量编译 确保子项目间依赖通过 project() 声明,Gradle 会自动计算变更范围,避免全量编译。
并行构建 在 gradle.properties 中设置 org.gradle.parallel=true,让无依赖关系的子项目并行编译。
配置缓存 开启 org.gradle.caching=true 和 org.gradle.configuration-cache=true,降低重复配置开销。