](https://i-blog.csdnimg.cn/direct/49f43100ad244966b9ad6d3a3fb61114.png)
作为 Java 开发者,大概率对 Maven + Java 项目的目录结构 烂熟于心:开发时将业务代码放在 src/main/java、配置文件塞到 src/main/resources,测试代码和测试资源则对应放进 src/test/java 和 src/test/resources—— 这套目录结构作为一种“约定”,使得开发人员无需额外配置,Maven 就能自动识别源码位置、处理资源文件,,完成编译打包。
当我们使用 Gradle 构建项目(尤其是 SpringBoot 项目)时,会发现这种熟悉感丝毫未减,因为 Gradle 深度兼容了 Maven 的目录约定,遵循 “约定优于配置” 原则,即便不写一行脚本,只要按上述目录存放代码和资源,Gradle 就能自动执行 compileJava(编译生产代码)、compileTestJava(编译测试代码)等核心任务。而支撑这一切 “无感知兼容” 的核心机制,正是 sourceSets(源码集)—— 它就像 Gradle 背后的 “约定执行者”,默默将目录规则与构建流程绑定。
本文将从 Gradle 项目的标准结构 入手,逐步拆解源码集的概念、默认配置与自定义实战,帮你既掌握 “约定” 的便捷性,又能灵活应对复杂项目的结构设计需求。
不同类型的项目(如 Java、Kotlin、Android)目录结构略有差异,本文以 Java 项目 为例
一、Gradle Java 项目的标准结构
1.1 单模块项目结构
一个典型的 Gradle 单模块项目(以 Java 应用为例)的目录集中在 src 下,所有 Java 源代码、测试代码及资源文件按类型(生产 / 测试)进行划分,比如 src/main/java 对应生产源码、src/test/resources 对应测试资源,典型结构如下:
gradle-project/
├── build.gradle.kts // 模块构建脚本(配置依赖、任务、源码集等)
├── settings.gradle.kts // 项目设置脚本(指定项目名称、包含的子模块)
└── src/
├── main/ // 生产环境核心代码(必选目录)
│ ├── java/ // Java 源代码(业务逻辑、工具类等)
│ └── resources/ // 生产资源文件(application.yml、静态资源等)
│
└── test/ // 测试代码(可选目录)
├── java/ // 测试 Java 源码(单元测试、测试工具类等)
└── resources/ // 测试资源文件(测试用配置、模拟数据等)
1.2 多模块项目的结构
当项目规模扩大时,通常会拆分为多模块(核心层 + 接口层 + 公共层),通过「父模块统一管理,子模块各司其职」降低耦合。典型多模块结构(以 SpringBoot 项目为例)如下:
gradle-project/
├── build.gradle.kts // 父模块构建脚本(统一管理子模块依赖版本、公共插件)
├── settings.gradle.kts // 项目设置脚本(声明子模块:common、core、web)
├── common/ // 子模块 1:公共工具模块(封装跨模块工具类、常量)
│ ├── build.gradle.kts // 子模块专属配置(如引入工具类依赖)
│ └── src/ // 子模块源码(遵循单模块目录约定)
│ ├── main/
│ └── test/
├── core/ // 子模块 2:核心业务模块(处理业务逻辑、数据访问)
│ ├── build.gradle.kts
│ └── src/
└── api/ // 子模块 3:api 接口模块
├── build.gradle.kts
└── src/
多模块项目中,父模块的
src目录通常不使用—— 所有 Java 源代码和资源由子模块各自维护,父模块仅负责全局配置(如依赖版本锁定、插件统一引入),避免子模块配置重复。
二、什么是 Source Sets?
在 Gradle 中,SourceSets 是对项目 “源码分组” 的抽象描述。它不仅定义了 “源码 / 资源该放在哪里”,还关联了 “该分组需要哪些依赖”“编译后输出到哪里”“对应的构建任务是什么”。
简单来说,Source Sets(源码集) 本质是「一组源代码目录 + 资源目录 + 关联任务」的集合。其核心思想是通过「目录」区分项目中不同类型的代码(如生产代码与测试代码),实现代码的隔离与复用;同时自动关联对应的编译、测试、打包等构建流程。
每个 SourceSet 包含以下关键组成部分,共同支撑对源码的全生命周期管理:
| 组成部分 | 说明 |
|---|---|
| 源代码目录 | 存放源代码文件,例如 src/main/java、src/test/java。 |
| 资源目录 | 存放非代码资源,如 src/main/resources(生产资源)、src/test/resources(测试资源)。 |
| 类路径 | 编译或运行时依赖的 JAR 包、库文件。 |
| 关联任务 | Gradle 自动创建的构建任务,如 compileJava(编译 Java 代码)、processResources(处理资源文件)、test(运行测试用例)等。 |
2.1 默认源码集
当项目引入 Java 插件(或基于其扩展的插件,如 java-library、application)后,Gradle 会自动创建 main 和 test 源码集:
| 源码集名称 | 用途 | 依赖关系 | 默认目录 |
|---|---|---|---|
main | 生产环境核心代码 | 无(其他源码集依赖它) | src/main/java、src/main/resources |
test | 单元测试 / 集成测试代码 | 依赖 main 源码集 | src/test/java、src/test/resources |

2.1.2 main 源码集
目录结构
main 源码集用于存放项目的核心业务代码和生产环境资源,包含 Java 源代码和资源文件两部分:
src/
└── main/
├── java/ # Java 源代码(核心业务逻辑)
└── resources/ # 生产环境资源(配置文件、静态资源等)
| 目录 | 用途 |
|---|---|
src/main/java/ | 存放 Java 源代码(核心业务逻辑代码) |
src/main/resources/ | 存放生产环境相关的资源文件(如配置文件、静态资源等) |
关联任务
Gradle 会为 main 源码集自动生成编译源码和处理资源的关联任务,在执行 build 等顶层构建命令时自动触发:
compileJava任务:负责编译src/main/java目录下的所有 Java 源代码,输出到build/classes/java/main目录。processResources任务:处理(复制 / 过滤)src/main/resources目录下的资源文件(如配置文件、静态资源等)到build/resources/main目录。
当执行 build 时,Gradle 会优先触发 processResources 和 compileJava任务:
compileJava完成后,build/classes/java/main中会生成所有生产代码的.class文件;
processResources完成后,build/resources/main中会生成可直接用于运行的资源文件;
最终这两个任务的输出(build/classes/java/main 和 build/resources/main)会作为输入,用于后续的 jar(打包)、assemble(聚合产物)等任务,最终生成可交付的 JAR/WAR 包。

2.2.2 test 源码集
目录结构
test 源码集用于存放验证 main 源码集功能的测试代码(如单元测试、组件测试),包含测试源代码和测试资源文件两部分:
src/
└── test/
├── java/ # 测试源代码(基于 JUnit、TestNG 等框架)
└── resources/ # 测试资源(测试配置、测试数据等)
| 目录 | 用途 |
|---|---|
src/test/java/ | 存放测试代码(单元测试、集成测试等),通常基于 JUnit、TestNG 框架。 |
src/test/resources/ | 存放测试资源文件(测试配置、测试数据等),运行测试时会自动加载。 |
关联任务
Gradle 会自动为 test 源码集生成以下核心任务支撑完整的测试执行流程:
compileTestJava:编译src/test/java目录下的测试源代码.java文件转换为.class字节码,输出到build/classes/java/test目录。processTestResources:处理src/test/resources目录下的测试资源文件,最终输出到build/resources/test目录。
执行 test 任务时,Gradle 会先执行 compileTestJava 和 processTestResources,确保测试代码和资源准备就绪,再通过测试框架(如 JUnit)执行测试用例,最终输出测试结果(成功 / 失败数量、耗时等)。
2.2 自定义任务查看 Source Sets
build.gradle.kts构建脚本中引入java插件:plugins { java }在
build.gradle.kts创建自定义sourceSets任务,打印项目所有的 Source Sets 信息:tasks.register("sourceSets") { doLast { // 获取所有的 sourceSets sourceSets.forEach { sourceSet -> println("Source Set: ${sourceSet.name}") // 输出 Java 源码目录的相对路径 sourceSet.java.srcDirs.forEach { println(" Java sources: ${project.relativePath(it)}") } // 输出资源目录的相对路径 sourceSet.resources.srcDirs.forEach { println(" Resources: ${project.relativePath(it)}") } } } }在项目根目录执行任务:
gradle sourceSets控制台输出以下:

三、自定义 integrationTest 源码集
默认的 main 和 test 足以满足简单项目需求,但对于复杂项目(如需要区分单元测试和集成测试),自定义源码集是更优选择,自定义源码集需结合「目录创建」「依赖配置」「任务绑定」三步。
以集成测试为例(与单元测试隔离,通常需要启动外部服务或数据库),我们将创建 integrationTest 源码集,实现代码隔离和独立执行。
3.1 创建目录结构
遵循 Gradle 源码集的约定优于配置原则,在 src 目录下创建 integrationTest 源码集的目录结构:
src/
├── integrationTest/ # 集成测试源码集
│ ├── java/ # 集成测试 Java 代码
│ └── resources/ # 集成测试资源(配置文件等)
├── main/
│ └── ...
└── test/
└── ...

3.2 配置源码集
在 build.gradle.kts 中通过 sourceSets 块添加 integrationTest 源码集配置,指定 integrationTest 源码集的目录路径和类路径,确保集成测试能访问业务代码和必要的依赖:
sourceSets {
// 定义名为 integrationTest 的源码集
create("integrationTest") {
// 配置源码目录
java {
srcDir("src/integrationTest/java") // Java 源码路径
}
resources {
srcDir("src/integrationTest/resources") // 资源路径
}
// 依赖 main 源码集的编译结果(即可以直接调用业务代码)
compileClasspath += sourceSets.main.get().output
runtimeClasspath += sourceSets.main.get().output
// 复用 test 源码集的依赖(如 JUnit 测试框架)
compileClasspath += sourceSets.test.get().output
runtimeClasspath += sourceSets.test.get().output
}
}
刷新 Gradle 后,IDE(如 IntelliJ IDEA)会自动识别为测试源码目录,无需额外配置:
3.3 关联任务
定义 integrationTest 源码集后,Gradle 会自动生成一系列任务用于处理源码编译、资源拷贝、清理等基础工作,命名遵循如下规则:
[固定前缀] + [源码集名称(驼峰命名)] + [固定后缀]
- 固定前缀:表示任务的 “核心动作”,由任务类型决定(如
compile代表编译,process代表资源处理)。 - 源码集名称(驼峰命名):关联的自定义源码集名称(如
integrationTest),与源码集一一对应。 - 固定后缀:表示任务的 “功能范围”(如
Java代表编译 Java 代码,Resources代表处理资源文件)。
结合 “自定义源码集 integrationTest” 为例:
| 任务类型 | 命名规则 | 示例(源码集:integrationTest) |
|---|---|---|
| 编译任务 | compile + [SourceSetName] + Java | compileIntegrationTestJava |
| 资源处理任务 | process + [SourceSetName] + Resources | processIntegrationTestResources |
| 聚合任务 | [SourceSetName] + Classes | integrationTestClasses |

3.4 添加依赖
集成测试需要测试框架(如 JUnit),需要配置依赖:
dependencies {
// 集成测试依赖 JUnit
testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.2")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.2")
}
3.5 创建集成测试任务
需要注册一个 Test 类型的任务,关联 integrationTest 源码集的编译结果,指定测试类路径和运行时路径,并配置测试执行规则(如框架、依赖顺序、过滤规则):
// 创建 integrationTest 任务
tasks.register<Test>("integrationTest") {
description = "执行集成测试"
group = "Verification" // 归类到「验证」分组(与 test 任务同组)
// 关联 integrationTest 源码集的编译结果和类路径
testClassesDirs = sourceSets["integrationTest"].output.classesDirs
classpath = sourceSets["integrationTest"].runtimeClasspath
// 配置测试框架
useJUnitPlatform()
// 过滤测试类(仅执行以 IntegrationTest 结尾的类)
//include("**/*IntegrationTest.java")
}
3.6 执行集成测试
创建集成测试代码:
src/integrationTest/java/example/NewIntegrationTest.javapublic class NewIntegrationTest { @Test public void test() { System.out.println("集成测试完成"); } }在项目根目录执行以下命令运行集成测试:
gradle integrationTest查看控制台输出测试通过信息:

浙公网安备 33010602011771号