本来没有想了解Gradle,但是在想看SpringBoot源码的时候发现,在SpringBoot2.2.8版本之后,不再使用maven进行构建,而是使用Gradle。想着把SpringBoot源码导入idea学习下源码,但是来来回回折腾了好几回,都是报错,想着不如学习下Gradle。
Gradle的官方介绍:
Gradle 是一种广泛使用且成熟的工具,拥有活跃的社区和强大的开发人员生态系统。
- Gradle 是 JVM 最常用的构建系统,也是 Android 和 Kotlin 多平台项目的默认系统。 它拥有丰富的社区插件生态系统。
- Gradle 可以使用其内置功能、第三方插件或自定义构建逻辑来自动化各种软件构建场景。
- Gradle 提供了一种高级、声明性且富有表现力的构建语言,使您可以轻松读取和编写构建逻辑。
- Gradle 速度快、可扩展,可以构建任何规模和复杂程度的项目。
- Gradle 可产生可靠的结果,同时受益于增量构建、构建缓存和并行执行等优化。
我简单的认知:可以用来管理项目需要的依赖,构建项目。
基本概念
Projects(项目):
就是整个项目工程,可以包含多个模块或者单模块的一个项目工程。
Build Scripts(构建脚本):
是一个脚本文件,写一些代码来规定如何构建项目。
Dependency Management(依赖关系管理):
管理项目结构和jar包的。
Tasks(任务):
任务是gradle的基本工作单元,在构建脚本中可以包含任意个工作单元,类似于一个java类中的方法,可以随意创建和定义,构建项目也像是一个个任务的执行。
Plugins(插件):
类似于java中的引包,引入插件,就可以在脚本中使用这个插件提供的方法。
Gradle项目结构
project
├── gradle 1️⃣
│ ├── libs.versions.toml 2️⃣
│ └── wrapper 3️⃣
│ ├── gradle-wrapper.jar 4️⃣
│ └── gradle-wrapper.properties 5️⃣
├── gradlew
├── gradlew.bat
├── settings.gradle(.kts) 6️⃣
├── subproject-a
│ ├── build.gradle(.kts) 7️⃣
│ └── src
└── subproject-b
├── build.gradle(.kts)
└── src
- 用于存储包装器文件等的 Gradle 目录
- 可以用来规定整个项目工程中的插件的版本
- 只是个目录
- 项目运行所需要的标准gradle安装包,为不同的用户和环境可以配置相同的gradle安装包,建议使用。
- 指定第四项中的包可以去哪里下载,可以指定本地地址,也可以使用镜像地址,还可以配置一些和安装包有关的配置。
- Gradle 设置文件,用于定义根项目名称和子项目等等,就相当于maven项目中跟项目的pom.xml
- 子项目的构建脚本
多项目构建
多项目构建有两种:
* 使用 buildSrc目录 的多项目构建: buildSrc目录放在根目录下一层中,也就是和根项目的子项目同层级。(SpringBoot源码就是用的这种方式)
* 复合构建: 官方文档中描述的:// <font style="color:rgb(2, 48, 58);">最适合在 builds(</font>_<font style="color:rgb(2, 48, 58);">不是子项目</font>_<font style="color:rgb(2, 48, 58);">)之间共享 logic 或隔离对共享 build logic(即约定插件)的访问。</font>
构建顺序
- 初始化 1. 检测settings.gradle文件 2. 创建Settings实例 3. 确定需要构建哪些模块(所以会在settings.gradle使用include标明有哪些模块) 4. 为每一个模块创建一个Project实例 2. 配置 1. 检测每个模块,也就是每个子项目中的build.gradle文件 2. 为请求的任务(就是task)创建任务图 3. 执行任务 1. 分析任务图的依赖关系 2. 执行任务
Settings.gradle文件(只有根目录会有)
```plain // 管理插件的 pluginManagement { // 这里定义的plugins只是为了限定版本号,并不会实际引入插件,还需要子项目的build.gradle中引入实际的plugin 但是不需要加上版本号了 // 配置插件下载的仓库地址 repositories { maven { url 'https://maven.aliyun.com/repository/gradle-plugin' } maven { url 'https://plugins.gradle.org/m2/' } mavenCentral() gradlePluginPortal() } // 可以对某个插件做特殊处理 resolutionStrategy { eachPlugin { if (requested.id.id == "org.jetbrains.kotlin.jvm") { useVersion "{kotlinVersion}" } if (requested.id.id == "org.jetbrains.kotlin.plugin.spring") { useVersion "{kotlinVersion}" } } } }
// 引入插件
plugins {
id "com.gradle.develocity" version "3.17.2"
id "io.spring.ge.conventions" version "0.0.17"
}
// 配置project实例的name属性,可以直接点击rootProject跳转到java类中,就可以查看可以配置哪些属性
rootProject.name="spring-boot-build"
// 项目加载完需要执行的回调
settings.gradle.projectsLoaded {
develocity {
buildScan {
def toolchainVersion = settings.gradle.rootProject.findProperty('toolchainVersion')
if (toolchainVersion != null) {
value('Toolchain version', toolchainVersion)
tag("JDK-KaTeX parse error: Expected 'EOF', got '}' at position 23: ...inVersion") }̲ def buildDi...{scan.buildScanUri}|build scan>\n"
}
}
}
}
// 标明有哪些模块
include "spring-boot-project:spring-boot-dependencies"
<h2 id="f8DHM">根目录的build.gradle</h2>
```plain
buildscript {
// 规定了所有模块中的build.gradle中需要用到的任务或者依赖,就到下面仓库中,只针对构建脚本
repositories {
maven { url 'https://maven.aliyun.com/repository/central' }
maven { url 'https://maven.aliyun.com/repository/public' }
maven {
url 'https://maven.aliyun.com/repository/apache-snapshots'
}
mavenLocal()
mavenCentral()
}
dependencies {
// 到上面指定的仓库去找这个依赖
classpath("io.spring.javaformat:spring-javaformat-gradle-plugin:0.0.15")
}
}
// 指定插件
plugins {
id "base"
// apply 默认是true, 表示自动开启,也可以配置为false,根据条件开启
id "org.jetbrains.kotlin.jvm" apply false // https://youtrack.jetbrains.com/issue/KT-30276
id "io.spring.nohttp" version "0.0.11"
}
allprojects {
// 设置了所有子项目都属于 org.springframework.boot 分组
group "org.springframework.boot"
// 定义了多个Maven仓库,项目实际代码中需要的依赖都到下面几个仓库去下载
repositories {
maven {
url 'https://maven.aliyun.com/repository/public/'
}
maven {
url 'https://maven.aliyun.com/repository/central'
}
mavenLocal()
mavenCentral()
}
configurations.all {
resolutionStrategy.cacheChangingModulesFor 0, "minutes"
}
}
// 找到名为checkstyleNohttp 任务并且配置maxHeapSize属性
tasks.named("checkstyleNohttp").configure {
maxHeapSize = "1536m"
}
// 添加一个任务
task.register("one") {
}
模块中的build.gradle
plain
// 标明当前模块需要哪些依赖,类似于pom文件
// 这里省略了版本号, 是因为在 spring-boot-dependencies中使用library方法规定了版本
// 类似于maven项目中专门用来放依赖的子项目,在这个pom文件已经指定了版本号,所以引用了这个项目的模块不需要额外写明版本号
dependencies {
// api 编译和运行时都需要的依赖项,并包含在已发布的 API 中
implementation 'org.springframework.boot:spring-boot-starter-web' // 编译和运行时都需要的依赖项
api("org.springframework:spring-core")
compileOnly 'org.projectlombok:lombok' // 仅编译所需的依赖项,不包含在 runtime 或发布中
runtimeOnly 'com.mysql:mysql-connector-j' // 仅在运行时需要的依赖项,不包含在 compile Classpath 中
annotationProcessor 'org.projectlombok:lombok' // 用于编译时注解处理的工具,它可以在编译时期处理注解,生成额外的代码
testImplementation 'org.springframework.boot:spring-boot-starter-test' // 编译和运行测试所需的依赖项。
testRuntimeOnly 'org.junit.platform:junit-platform-launcher' // 仅运行测试所需的依赖项
}
api 编译和运行时都需要的依赖项,并包含在已发布的 API 中。
implementation 编译和运行时都需要的依赖项。
compileOnly 仅编译所需的依赖项,不包含在 runtime 或发布中。
compileOnlyApi 依赖项仅需要用于编译,但包含在已发布的 API 中。
runtimeOnly 仅在运行时需要的依赖项,不包含在 compile Classpath 中。
testImplementation 编译和运行测试所需的依赖项。
testCompileOnly 仅测试编译所需的依赖项。
testRuntimeOnly 仅运行测试所需的依赖项。
// 将properties 写入到这个目录中的springBootVersion文件中
sourceSets {
main {
java {
srcDirs syncJavaTemplates
}
}
test {
output.dir(tomcatConfigProperties, builtBy: "extractTomcatConfigProperties")
}
}
//
def syncJavaTemplates = tasks.register("syncJavaTemplates", Sync) {
from("src/main/javaTemplates")
into("build/generated-sources/main")
def properties = ["springBootVersion": project.version]
expand(properties)
inputs.properties(properties)
}