Gradle 的项目结构与源码集(Source Sets)详解(Kotlin DSL)
](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 {// 获取所有的 sourceSetssourceSets.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().outputruntimeClasspath += sourceSets.main.get().output// 复用 test 源码集的依赖(如 JUnit 测试框架)compileClasspath += sourceSets.test.get().outputruntimeClasspath += 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 {// 集成测试依赖 JUnittestImplementation("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.classesDirsclasspath = sourceSets["integrationTest"].runtimeClasspath// 配置测试框架useJUnitPlatform()// 过滤测试类(仅执行以 IntegrationTest 结尾的类)//include("**/*IntegrationTest.java")
}
3.6 执行集成测试
- 
创建集成测试代码: src/integrationTest/java/example/NewIntegrationTest.javapublic class NewIntegrationTest {@Testpublic void test() {System.out.println("集成测试完成");}}
- 
在项目根目录执行以下命令运行集成测试: gradle integrationTest
- 
查看控制台输出测试通过信息:  
