2021-12-29
Gradle
M_Gradle 官网 - 发布下载页面 官网 - Gradle User Manual 官网 - 核心插件 官网 - Kotlin - DLS API
Gradle is an open-source build automation tool focused on flexibility(专注灵活性) and performance.
projects 和 tasks
projects 和 tasks是 Gradle 中最重要的两个概念;
projects 项目
任何一个 Gradle 构建都是由一个或多个 projects 组成; 每个 project 包括许多可构建组成部分; 这完全取决于你要构建些什么; 举个例子, 每个 project 或许是一个 jar 包或者一个 web 应用, 它也可以是一个由许多其他项目中产生的 jar 构成的 zip 压缩包;
一个project代表一个正在构建的组件(Jar/war文件),当构建开始时,Gradle会基于build.gradle实例化一个 org.gradle.api.Project 对象,并通过project变量来隐式调用其成员。
将build.gradle配置封装为一个Project对象,对象名字为 project,通过 project 可以隐式调用:默认使用groovy 语法
tasks 任务
每个 project 都由多个 tasks 组成; 每个 task 都代表了构建执行过程中的一个原子性操作; 如编译, 打包, 生成 javadoc, 发布到某个仓库等操作;
Gradle 项目实例
Gradle 目录说明
https://docs.gradle.org/current/userguide/partr1_gradle_init.html
.
├── gradle 1
│ └── wrapper
├── gradlew 2
├── gradlew.bat 2
├── settings.gradle.kts 3
└── app
├── build.gradle.kts 4
└── src
├── main
│ └── java 5
│ └── demo
│ └── App.java
└── test
└── java 6
└── demo
└── AppTest.java- Generated folder for wrapper files
- Gradle wrapper start scripts (启动脚本)
- Settings file to define build name and subprojects
- Build script for app subproject
- Default Java source folder for app subproject
- Default Java test source folder for app subproject
settings.gradle.kts 配置文件
rootProject.name = "authoring-tutorial"
include("app")
include("subject01")
include("subject02")
...rootProject.name 为构建分配一个名称 include(“app”)定义构建由一个名为app的子项目组成,该子项目包含自己的源代码和构建逻辑。
build.gradle.kts 配置文件
每个项目,对应一个 build.gradle 的构建脚本
plugins { 1
id("application")
}
repositories { 2
mavenCentral()
}
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter:5.9.3") 3
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
implementation("com.google.guava:guava:32.1.1-jre") 4
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(11) 5
}
}
application {
mainClass = "org.example.App" 6
}
tasks.named<Test>("test") {
useJUnitPlatform() 7
}
- 用于引入 Gradle 插件, 对用Java构建CLI应用程序的支持。
- 使用 Maven Central解决依赖关系。
- 测试代码编译和运行时依赖。
- 声明项目依赖。
- 定义工具链版本。
- 定义应用程序的主类。
- 使用JUnit平台进行单元测试
插件 plugin
用于引入 Gradle 插件,类似于 Maven 的 <packaging> 和插件配置。
id:插件 ID,内置插件(如java)无需版本号。version:第三方插件版本号(可选)。apply false:声明插件但不立即应用(用于多模块项目)。
仓库配置 (repositories)
声明依赖仓库,类似于 Maven 的 <repositories>。
常用仓库:
mavenCentral():Maven 中央仓库。mavenLocal():本地 Maven 仓库。google():Google 的 Maven 仓库。
repositories {
// 改为阿里云的镜像地址
maven { setUrl("https://maven.aliyun.com/repository/central") }
maven { setUrl("https://maven.aliyun.com/repository/jcenter") }
maven { setUrl("https://maven.aliyun.com/repository/google") }
maven { setUrl("https://maven.aliyun.com/repository/gradle-plugin") }
maven { setUrl("https://maven.aliyun.com/repository/public") }
mavenCentral()
gradlePluginPortal()
}依赖配置 (dependencies)
dependencies {
//依赖当前项目下的某个模块[子工程]
implementation project(':subject01')
//直接依赖本地的某个jar文件
implementation files('libs/foo.jar', 'libs/bar.jar')
//implementation(fileTree("D:\\library\\javafx-sdk-24.0.1\\lib")) // 自动包含目录下所有 JAR
//配置某文件夹作为依赖项
implementation fileTree(dir: 'libs', include: ['*.jar'])
//直接依赖
implementation 'org.apache.logging.log4j:log4j:2.17.2'
}implementation:主代码编译和运行时依赖。testImplementation:测试代码编译和运行时依赖。compileOnly:仅编译时依赖(类似 Maven 的provided)runtimeOnly:仅运行时依赖(类似 Maven 的runtime)
扩展配置 (extensions)
配置插件提供的扩展属性
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(21)) // 指定 JDK 版本
}
}java:Java 插件提供的扩展。kotlin:Kotlin 插件提供的扩展。
附 作用域配置对象表格
| 名称/方法 | 类型/接口 | 作用 | 示例 | 常用方法/配置 |
|---|---|---|---|---|
buildscript | ScriptHandler | 配置构建脚本自身的依赖(如插件、工具) | groovy<br>buildscript {<br> repositories { mavenCentral() }<br>} | repositories {}、dependencies {} |
plugins | PluginDependenciesSpec | 声明或应用插件 | groovy<br>plugins {<br> id 'java'<br>} | id()、version()、apply() |
allprojects | 方法(接收闭包) | 为所有项目(包括根项目)配置公共属性 | groovy<br>allprojects {<br> version = '1.0.0'<br>} | 闭包内可配置任意 Project 属性或任务 |
subprojects | 方法(接收闭包) | 仅配置子项目(排除根项目) | groovy<br>subprojects {<br> apply plugin: 'java'<br>} | 闭包内配置子项目属性或任务 |
repositories | RepositoryHandler | 配置依赖仓库地址 | groovy<br>repositories {<br> mavenCentral()<br>} | mavenCentral()、google()、jcenter() |
dependencies | DependencyHandler | 添加项目依赖(如第三方库) | groovy<br>dependencies {<br> implementation 'com.example:lib:1.0'<br>} | implementation()、testImplementation() |
configurations | ConfigurationContainer | 管理自定义依赖配置 | groovy<br>configurations {<br> customConfig<br>} | 定义新配置(如 customConfig) |
artifacts | ArtifactHandler | 定义发布的构件(需配合插件使用) | groovy<br>artifacts {<br> archives file('libs/example.jar')<br>} | archives()、file() |
tasks | TaskContainer | 管理项目中的任务(创建、配置任务) | groovy<br>tasks.register('hello') {<br> doLast { println 'Hello!' }<br>} | register()、create()、configure() |
| Project 属性 | Project 对象属性 | 直接配置根项目的属性 | groovy<br>version = '1.0.0'<br>group = 'com.example' | version、group、description |
ext | 扩展属性 | 定义全局共享的自定义属性 | groovy<br>ext {<br> kotlinVersion = '1.8.0'<br>} | 通过 ext {} 块定义属性 |
gradle.properties 配置文件
配置 Gradle 运行的JDK
Gradle 提供了几个选项,可以轻松地配置将用于执行构建的Java进程。
可以通过GRADLE_OPTS或JAVA_OPTS在本地环境中配置这些设置,但能够在版本控制中存储某些设置(如JVM内存配置和JAVA_HOME位置)是很有用的,这样整个团队就可以在一致的环境中工作。
另外在本地仓库根目录的 F:\gradle_local_repository\gradle.properties 亦有效的!!
要执行此操作,请将这些设置放入grade.properties文件中
配置代理
1、全局gradle使用代理:{userdir}/.gradle/gradle.properties
在gradle.properties加入如下内容:
gradle.properties
systemProp.http.proxyHost=127.0.0.1
systemProp.http.proxyPort=10808
systemProp.https.proxyHost=127.0.0.1
systemProp.https.proxyPort=10808
# 对于国内的仓库可以不走代理,还有部分内网地址也可以不走代理
systemProp.http.nonProxyHosts=developer.huawei.com|maven.aliyun.com|192.168.*
buildSrc
运行 Gradle 时会检查项目中是否存在一个名为 buildSrc 的目录。然后 Gradle 会自动编译并测试这段代码,并将其放入构建脚本的类路径中, 对于多项目构建,只能有一个 buildSrc 目录,该目录必须位于根项目目录中, buildSrc 是 Gradle 项目根目录下的一个目录,它可以包含我们的构建逻辑,与脚本插件相比,buildSrc 应该是首选,因为它更易于维护、重构和测试代码
依赖冲突
假设你的项目依赖于一个库,而这个库又依赖于其他库。你不必自己去找出所有这些依赖,你只需要加上你直接依赖的库,Gradle会隐式的把这些库间接依赖的库也加入到你的项目中。
(1)依赖传递性:
假设你的项目依赖于一个库,而这个库又依赖于其他库。你不必自己去找出所有这些依赖,你只需要加上你直接依赖的库,Gradle会隐式的把这些库间接依赖的库也加入到你的项目中。

(2)传递性依赖中版本冲突:
由于传递性依赖的特点,两个不同版本的jar包会被依赖进来,这样就存在版本冲突的问题。

maven中解决冲突的办法
【1】第一原则:最短路径优先原则
“最短路径优先”意味着项目依赖关系树中路径最短的版本会被使用。
例如,假设A、B、C之间的依赖关系是A→B→C→D(2.0) 和A→E→(D1.0),那么D(1.0)会被使用,因为A通过E到D的路径更短。
【2】第二原则:最先声明原则
依赖路径长度是一样的的时候,第一原则不能解决所有问题,比如这样的依赖关系:A–>B–>Y(1.0),A–>C–>Y(2.0),Y(1.0)和Y(2.0)的依赖路径长度是一样的,都为2。那么到底谁会被解析使用呢?在maven2.0.8及之前的版本中,这是不确定的,但是maven2.0.9开始,为了尽可能避免构建的不确定性,maven定义了依赖调解的第二原则:第一声明者优先。在依赖路径长度相等的前提下,在POM中依赖声明的顺序决定了谁会被解析使用。顺序最靠前的那个依赖优胜。
Gradle中解决冲突的办法
(4)Gradle中解决冲突的办法-自动解决方案:
Gradle的默认自动解决版本冲突的方案是选用版本最高的。
案例:加入两个依赖:
implementation group: 'org.springframework', name: 'spring-jdbc', version: '5.1.3.RELEASE'
implementation group: 'org.springframework', name: 'spring-webmvc', version: '5.1.13.RELEASE'

(5)Gradle中解决冲突的办法-手动修改依赖:
手动排除依赖:
dependencies {
implementation(group: 'org.springframework', name: 'spring-jdbc', version: '5.1.3.RELEASE'){
exclude group:'org.springframework',module:'spring-beans'
}
}
项目打包发布
Spring Boot 项目打包 jar & lib依赖分离
- 禁用bootJar任务,启用jar任务。
- 配置jar任务的manifest,设置Main-Class为应用程序的主类(例如com.example.ApplicationKt),而不是Spring Boot的Launcher。
- 在manifest中设置Class-Path为lib/下的所有依赖jar。
- 创建一个任务将runtimeClasspath的依赖复制到build/libs/lib目录。
tasks.register<Copy>("copyJar")
// 复制jar依赖包
tasks.named<Copy>("copyJar") {
//buildDir 属性已被弃用 使用 layout
delete("${layout.buildDirectory.asFile.get()}/libs/lib")
from(configurations.runtimeClasspath).into("${layout.buildDirectory.asFile.get()}/libs/lib")
}
// 打包时排除其他依赖jar
tasks.named<org.springframework.boot.gradle.tasks.bundling.BootJar>("bootJar") {//修改 bootJar 打包行为
setExcludes(listOf("*.jar"))
dependsOn("copyJar")
manifest {
// 指定Class-Path, 可以在运行时不用指定 loader.path 参数
attributes(
"Class-Path" to configurations.runtimeClasspath.get().files.map { "lib/${it.name}" }.joinToString(" ")
)
}
}- 执行命令
./gradlew buildbuild 构建完成后,build/libs 目录将包含:
- 主 jar 文件(如
app.jar) lib目录(包含所有依赖的 jar)
Kotlin Application 项目打包 jar & lib依赖分离
plugins {
id("java")
id("org.jetbrains.kotlin.jvm") version "2.2.20"
}
dependencies {
.................
}
// 1. 配置 `jar`任务
tasks.jar {
manifest {
attributes(
"Main-Class" to "org.yang.pdf.classify.MainKt", // 替换为你的主类
"Class-Path" to configurations.runtimeClasspath.get()
.files.joinToString(" ") { "lib/${it.name}" }
)
}
}
val V_BuildDir = layout.buildDirectory.asFile.get()
// 2. 复制依赖任务
tasks.register<Copy>("copyDependencies") {
from(configurations.runtimeClasspath)
into("${V_BuildDir}/libs/lib")
}
// 3. 完整打包任务
tasks.register<Zip>("buildDist") {
dependsOn("jar", "copyDependencies")
archiveFileName.set("${project.name}-dist.zip")
destinationDirectory.set(V_BuildDir.resolve("dist"))
from(V_BuildDir.resolve("libs")) {
include("*.jar")
include("lib/**")
}
}
镜像源
https://developer.aliyun.com/mvn/guide
for java
Gradle 不支持镜像源的直接设置,只能通过 maven() 方法设置一个新的 Maven 仓库地址。
在项目中的 build.gradle(Project)修改内容
buildscript {
repositories {
maven {
url 'https://maven.aliyun.com/repository/public/'
}
maven {
url 'https://maven.aliyun.com/repository/google/'
}
}
dependencies {
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
maven{ url 'http://maven.aliyun.com/nexus/content/repositories/jcenter'}
}
}另外又加了个 jcenter 仓库, 下载也是慢(jcenter是一个由 bintray.com维护的Maven仓库)
buildscript {
ext.anko_version = '0.10.8'
ext.kotlin_version = '1.3.72'
ext.retrofit_version = '2.4.0'
repositories {
jcenter()
将 jcenter() 改为mavenCentral(), 或者删掉
for kotlin
在 gradle.kts 中配置
settings.gradle.kts
pluginManagement {
repositories {
// 改为阿里云的镜像地址
maven { setUrl("https://maven.aliyun.com/repository/central") }
maven { setUrl("https://maven.aliyun.com/repository/jcenter") }
maven { setUrl("https://maven.aliyun.com/repository/google") }
maven { setUrl("https://maven.aliyun.com/repository/gradle-plugin") }
maven { setUrl("https://maven.aliyun.com/repository/public") }
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
// 改为阿里云的镜像地址
maven { setUrl("https://maven.aliyun.com/repository/central") }
maven { setUrl("https://maven.aliyun.com/repository/jcenter") }
maven { setUrl("https://maven.aliyun.com/repository/google") }
maven { setUrl("https://maven.aliyun.com/repository/gradle-plugin") }
maven { setUrl("https://maven.aliyun.com/repository/public") }
mavenCentral()
}
}
rootProject.name = "My Application"
include(":app")
修改
file/C:\\Users\\yang\\Downloads\\gradle-8.4-bin.zip
复用 maven 本地仓库资源
在本地开发环境中已经有一个Maven仓库, Gradle能够使用这些本地的依赖, 而不是重新从远程仓库下载。
repositories {
mavenLocal{setUrl("file:///F:\\gradle_local_repository")} // 优先从本地仓库查找依赖
maven { setUrl("https://maven.aliyun.com/repository/public") } // 镜像源
mavenCentral()// 最后查找中央仓库
}