Gradle项目结构
项目结构
前置条件
注意
这一步骤是在自己本机电脑配置
配置文件(gradle.properties)
在公司项目中,我们需要配置隐私信息以使用公司的私有 Maven 仓库。
在用户目录下的 .gradle 文件夹中创建一个 gradle.properties 文件,内容如下:
如果没有自定义路径,.gradle 通常位于当前用户目录。
Macos:/Users/用户名/.gradle
Windows:C:\Users\用户名\.gradle
Linux:/home/用户名/.gradle
# 公司的nexus maven仓库链接地址都是固定的不用变 key为固定值 不可更改项目里会读取 添加company前缀 便于区分
companyNexusSnapshotsRepoUrl=https://nexus.tiangong.site/repository/aikero-snapshots
companyNexusReleasesRepoUrl=https://nexus.tiangong.site/repository/aikero-releases
companyNexusRepositoryUrl=https://maven.szzhijing.com/repository/aikero-public
companyNexusUsername=你自己Nexus的账号名
companyNexusPassword=你自己Nexus的密码
catalogPluginVersion=2.0.0
# catalogPluginVersion 这里会提供一个默认的目录插件版本
# springboot 2.x 使用2.0.0
# springboot 3.x 使用3.0.1配置初始化文件(init.gradle.kts)
在用户目录的.gradle文件夹中创建init.gradle.kts文件,用于进行全局初始化配置。
例如: 对于不适合发布到 Gradle 插件中心或 Nexus 的插件,可以在此文件中统一配置。
我司的配置如下:
// # https://docs.gradle.org/current/userguide/plugins.html#sec:plugin_management
beforeSettings {
val catalogPluginVersion: String by settings
pluginManagement {
repositories {
mavenLocal()
maven {
url = uri(providers.gradleProperty("companyNexusRepositoryUrl").get())
isAllowInsecureProtocol = true
credentials {
username = providers.gradleProperty("companyNexusUsername").get()
password = providers.gradleProperty("companyNexusPassword").get()
}
}
gradlePluginPortal()
}
plugins {
id("team.aikero.gradle.plugin.version-catalog") version "${catalogPluginVersion}" // 这里获取的是 gradle.properties 里的catalogPluginVersion版本号
id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
}
}
}提示
将这部分放在初始化脚本中是因为这些配置通常是固定的,不易发生变化。如果将其放在项目中,将会显得非常繁琐。此外,插件 catalog 和 toolchains 也配置了版本号。如果将配置放在项目中,当插件版本需要强制升级时,所有服务代码都必须进行修改。而将其放在初始化脚本中,只需修改一次,便能确保所有相关服务都能适应新的配置。
- 覆盖版本配置
正如第二点的TIP所言,一般来说不需要在项目中配置插件仓库,但若插件开发者 或者 有临时的仓库需要配置的话,可以在特性的项目当中覆盖初始化脚本的配置。
按照Gradle的优先级,项目中的配置会覆盖全局配置,像正常一样在项目中settings.gradle.kts配置即可
// 可以覆盖插件仓库配置 在公司的项目 一般都不需要这么做 都配好了
pluginManagement {
repositories {
mavenLocal()
maven {
url = uri(providers.gradleProperty("companyNexusRepositoryUrl").get())
isAllowInsecureProtocol = true
credentials {
username = providers.gradleProperty("companyNexusUsername").get()
password = providers.gradleProperty("companyNexusPassword").get()
}
}
gradlePluginPortal()
}
}
plugins {
id("team.aikero.blade.gradle.plugin.version-catalog") version ("自定义的版本号") // 最有可能的是修改自定义版本号
id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
// 增加其他的插件
}
// 增加其他的自定义配置项目结构
Gradle
drawer
├── README.md // 项目的说明文档,通常描述项目的概述和使用方式
├── build.gradle.kts // 项目的顶级构建脚本,使用 Kotlin DSL 编写
├── drawer-common // 公共模块,用于储存可被其他模块复用的代码
│ └── build.gradle.kts // drawer-common模块的构建脚本,定义模块级别的构建配置
├── drawer-sdk // SDK模块,feign 调用接口 这里的结构通常是 部门内部的服务之间的调用 不属于外部(跨部门)SDK
│ ├── build.gradle.kts // drawer-sdk模块的构建脚本,定义模块级别的构建配置
│ └── src // SDK模块的源代码目录
├── drawer-service // 服务模块,包含服务端应用的相关代码
│ ├── build.gradle.kts // drawer-service模块的构建脚本,定义模块级别的构建配置
│ └── src // 服务模块的源代码目录
│ └── application.yml // 服务模块的配置文件
├── gradle // Gradle相关的附加配置和脚本目录
│ ├── gradle.properties // 额外的全局属性配置
│ └── wrapper // Gradle Wrapper相关文件,确保使用指定版本的Gradle
├── gradle.properties // 项目的全局属性配置文件
├── gradlew // Unix可执行的Gradle Wrapper脚本,用于确保使用正确的Gradle版本
├── gradlew.bat // Windows可执行的Gradle Wrapper脚本
└── settings.gradle.kts // 使用Kotlin DSL编写的项目设置文件,定义项目模块等信息gradle.properties 注意事项
此文件必须拥有以下 key 来描述项目信息,CI流程会强制校验相关信息,否则无法合并代码
group:项目的组名,通常是公司或组织的域名反转形式version:项目的版本号,遵循语义化版本控制(SemVer)规范frameworkVersion:项目所使用的框架版本,通常是一个特定的版本号
group=team.aikero.playground
version=0.0.20
frameworkVersion=3.1.1关于SDK模块的说明
警告
SDK模块的存在通常是 部门内部的服务之间的调用 不属于外部(跨部门)SDK 它应该保持最纯净的代码,尤其依赖上是干干净净的
SDK的内容应当只包含:
- 对本项目需要开放的接口的定义
- 接口需要的实体类定义
结构
├── build.gradle.kts
└── src
└── main
├── kotlin
│ └── team
│ └── aikero
│ └── drawer
│ └── sdk
│ ├── FeignAutoConfiguration.kt # 自动配置 扫描feign接口
│ ├── client
│ │ └── DrawerClient.kt # feign接口
│ ├── constant
│ │ └── PathConstant.kt # 路径常量
│ └── vo
│ └── req
│ └── DrawerSearchReq.kt # 请求参数
└── resources
└── META-INF
└── spring
└── org.springframework.boot.autoconfigure.AutoConfiguration.imports # 自动配置导入文件依赖
SDK包的依赖尤其需要干净,不应该包含任何不必要的依赖,当使用方服务依赖SDK包时,可以不用担心SDK包的依赖会带来额外的依赖,导致项目冲突
plugins {
alias(commonLibs.plugins.kotlin.jvm)
alias(commonLibs.plugins.publish.conf)
alias(commonLibs.plugins.common.conf)
alias(commonLibs.plugins.api.version.generator)
}
dependencies {
api(projects.drawerCommon)
implementation(commonLibs.blade.common)
compileOnly(springCloudLibs.spring.springCloudOpenfeignCore) # feign依赖注意一定要是compileOnly 不传递依赖
}通常项目settings.gradle.kts文件中配置如下:
import team.aikero.gradle.plugin.version.catalog.versionCatalogConf
plugins {
id("team.aikero.gradle.plugin.version-catalog")
id("org.gradle.toolchains.foojay-resolver-convention")
}
rootProject.name = "drawer"
val frameworkVersion: String by settings
include(
"drawer-common",
"drawer-sdk",
"drawer-service",
)
versionCatalogConf {
artifactVersion = frameworkVersion
}如需要 自定义 插件仓库地址和增添插件,参考上面的覆盖配置
application.yml
spring:
application:
name: demo-service # 应用程序的名称,用于标识该服务,通常与微服务名称一致
cloud:
nacos:
config:
username: ${NACOS_USERNAME} # 从环境变量或其他配置源读取 Nacos 用户名,用于身份验证
password: ${NACOS_PASSWORD} # 从环境变量或其他配置源读取 Nacos 密码,用于身份验证
server-addr: ${NACOS_SERVER_ADDR} # Nacos 服务器地址,配置中心的连接地址
namespace: ${NACOS_NAMESPACE} # Nacos 中的命名空间,便于逻辑隔离不同的配置和服务
group: ${NACOS_GROUP} # 配置所在的组,用于进一步组织和隔离配置
file-extension: ${NACOS_FILE_EXTENSION} # 配置文件的扩展名,如 yml 或 properties,定义配置格式
config:
import: # 依据项目需要自行导入需要的配置项 具体查看nacos
- optional:file:./bootstrap.yml # 可选地从本地文件系统导入配置文件 `bootstrap.yml`
- optional:nacos:yunwei-db.yml # 可选地从 Nacos 导入 `yunwei-db.yml` 配置文件
- optional:nacos:yunwei-resources-config.yml # 可选地从 Nacos 导入 `yunwei-resources-config.yml` 配置文件
- optional:nacos:nacos-register.yml # 可选地从 Nacos 导入 `nacos-register.yml` 配置文件
- optional:nacos:common-configuration.yml # 一些公共的配置 一般需要配置
- optional:nacos:${spring.application.name}.yml # 可选地从 Nacos 导入 `${spring.application.name}.yml` 配置文件,动态应用名称
- optional:nacos:${spring.application.name} # 可选地从 Nacos 导入不带扩展名的配置,动态应用名称创建项目
Gradle版本升级
Gradle版本在项目中通过Wrapper机制进行管理,配置文件路径为:
$项目根目录/gradle/wrapper/gradle-wrapper.properties标准的配置文件内容如下:
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://jv-yunwei.oss-cn-hangzhou.aliyuncs.com/gradle/gradle-8.14.3-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists提示
我们使用内网地址 https://jv-yunwei.oss-cn-hangzhou.aliyuncs.com/gradle/ 来加速Gradle的下载,避免网络问题导致的构建失败。
执行升级命令
使用以下命令升级到指定版本:
# 升级到如8.14.3
./gradlew wrapper --gradle-version=8.14.3 --gradle-distribution-url=https://jv-yunwei.oss-cn-hangzhou.aliyuncs.com/gradle/gradle-8.14.3-bin.zip回滚操作
如果升级后出现问题,可以快速回滚使用命令或者直接撤销git变更:
# 回滚到之前的版本(例如8.5)
./gradlew wrapper --gradle-version=8.14.2 --gradle-distribution-url=https://jv-yunwei.oss-cn-hangzhou.aliyuncs.com/gradle/gradle-8.14.2-bin.zipConfiguration Cache 注意事项
注意
从 Gradle 9.0 开始,Configuration Cache 已成为稳定功能,并且新初始化的项目默认开启。在 gradle.properties 中启用 org.gradle.configuration-cache=true 后,需要特别注意代码生成工具的兼容性问题。
什么是 Configuration Cache?
Configuration Cache 是 Gradle 的一个性能优化功能,它缓存了项目配置阶段的结果。启用后,Gradle 可以跳过配置阶段,直接进入执行阶段,从而加快构建速度。
启用方式
在 gradle.properties 中添加:
org.gradle.configuration-cache=true
# 以下顺带配置 显式查看更有助于理解
org.gradle.parallel=true
org.gradle.caching=true常见问题
1. Jimmer DTO 文件 刷新问题
问题描述:
- 使用 Jimmer ORM 的
.dto文件时,修改src/main/dto目录下的文件后,KSP 没有重新生成代码,而是使用了缓存
原因:
.dto文件位于src/main/dto目录,不在标准的 Kotlin 源码路径 (src/main/kotlin) 中- Configuration Cache 模式下,Gradle 的任务输入追踪可能不会自动监控这个非标准目录
解决方案:
在 build.gradle.kts 中显式配置 KSP 任务的输入:
// oplog-service/build.gradle.kts
tasks.matching { it.name.startsWith("ksp") }.configureEach {
inputs.dir("src/main/dto")
.withPropertyName("dtoFiles")
.withPathSensitivity(PathSensitivity.RELATIVE)
}工作原理:
- ✅ 当
src/main/dto目录下的文件被修改时,Gradle 检测到 inputs 变化 - ✅ KSP 任务被标记为
OUT-OF-DATE,重新执行并生成代码 - ✅ 当没有文件修改时,KSP 任务标记为
UP-TO-DATE,使用缓存,提高构建速度
验证方法:
# 1. 清理构建
./gradlew clean
# 2. 首次构建
./gradlew build --info | grep -i kspKotlin
# 3. 修改 src/main/dto 下的任意 .dto 文件
# 例如: 添加一个新字段或注释
# 显示 kspKotlin
# 4. 再次构建,观察 KSP 任务是否重新执行
./gradlew build --info | grep -i kspKotlin
# 显示 kspKotlin UP-TO-DATE
# 也可以查看 build 目录下的 ksp相关文件夹