Gradle 是一种开源构建自动化工具,可以构建几乎任何类型的软件。Gradle 对您要构建什么或如何构建它几乎没有任何假设。这使得 Gradle 特别灵活。Gradle 构建脚本是使用 Groovy 或 Kotlin DSL 编写的。在深入了解 Gradle 的细节之前,了解以下术语会很有帮助。
一、术语
- 项目:Gradle 构建的东西。项目包含一个构建脚本,它是一个位于项目根目录中的文件,通常名为build.gradle或build.gradle.kts. 构建脚本为该项目定义任务、依赖项、插件和其他配置。单个构建可以包含一个或多个项目,每个项目可以包含自己的子项目。
- 任务:任务包含执行某些工作的逻辑——编译代码、运行测试或部署软件。在大多数项目中使用Gradle提供的内置任务就足够了。比如TestGradle 提供了实现许多常见构建系统需求的任务,任务本身包括:
- 动作:做某事的工作片段,例如复制文件或编译源代码
- 输入:操作使用或操作的值、文件和目录
- 输出:操作修改或生成的文件和目录
- 插件:插件允许您将新概念引入到任务、文件和依赖配置之外的构建中。例如,大多数语言插件将源集的概念添加到构建中。使用插件,您可以编写一次任务并在多个构建中使用它。或者,您可以将常用配置(如日志记录、依赖项和版本管理)存储在一个位置,这可减少了构建脚本中的重复,大大提高易用性和效率。
二、构建工具分类
常见的构建工具主要有三种:Ant、Maven、Gradle。Ant现在使用的不是太多,至少在国内是这样。如果对Maven已经非常熟悉了,可能不太愿意使用gradle,感觉貌似没有必要。但是既然gradle出现了就说明有很多人对Maven还是有一定的意见。因此在这里我来总结一下gradle相比maven的优势。
下图来源于官网:
- 速度:gradle使用构建缓存、守护进程等方式提高编译速度。结果就是gradle的编译速度要远超maven,平均编译速度比Maven快好几倍,而且项目越大,这个差距就越明显。
- 灵活性:gradle要比Maven灵活太多,虽然有时候灵活并不是一件好事情。但是大部分情况下,灵活一点可以极大的方便我们。Maven死板的XML文件方式做起事情来非常麻烦。很多Maven项目都通过执行外部脚本的方式来完成一些需要灵活性的工作。而在gradle中配置文件就是构建脚本,构建脚本就是编程语言,完全可以自给自足,无需外部脚本。
- 简洁性:gradle脚本的长度要远远短于maven配置文件的长度。虽然很多人都说XML维护起来不麻烦,但是我觉得,维护一个光是依赖就有几百行的XML文件,不见得就比gradle脚本简单。
也许是因为我上面说的原因,也许有其他原因,不得不承认的一件事情就是gradle作为一个新兴的工具已经有了广泛的应用。spring等项目已经从Maven切换到了gradle。开发安卓程序也只支持gradle了。因此不管是否现在需要将项目从maven切换到gradle,但是至少学习gradle是一件必要的事情。
二、安装Gradle
安装 Gradle 之前首先要确保我们已经在系统中安装了 JDK,并且JDK的版本最低在1.7。最新的Gradle版本需要JDK1.8及以上,官网文档地址:https://docs.gradle.org/,详细可参考官方文档。如果是Java项目建议直接采用IDE方式安装,比如IntelliJ IDEA,IDEA不仅自带了Maven构建工具,还可以在创建项目的时候选择Gradle创建项目。
2.1、全局配置
同Maven一样,安装成功后或是创建了一个Gradle项目后,一般会在当前系统用户的根目录下创建仓库。如下图所示,其中/Users/liudong/.gradle 就是Gradle的默认本地仓库地址,最初时没有gradle.properties和init.gradle这两个文件,需要手动添加,这两个文件就是全局配置文件。但建议每到一个公司就修改一个目录(习惯问题,可按个人习惯决定是否分开)
- cachs\modules-2:所有依赖的jar包的缓存目录;
- wrapper\dists:所有下载的不同版本的Gradle存放地址目录;
配置全局仓库
在gradle中配置下载镜像需要在/Users/liudong/.gradle文件夹中新建一个init.gradle初始化脚本,这样一来,gradle下载镜像的时候就会使用这里配置的镜像源下载,速度会快很多,脚本文件内容如下:
allprojects {
repositories {
maven {
url "https://maven.aliyun.com/repository/public"
}
maven {
url "https://maven.aliyun.com/repository/jcenter"
}
maven {
url "https://maven.aliyun.com/repository/spring"
}
maven {
url "https://maven.aliyun.com/repository/spring-plugin"
}
maven {
url "https://maven.aliyun.com/repository/gradle-plugin"
}
maven {
url "https://maven.aliyun.com/repository/google"
}
maven {
url "https://maven.aliyun.com/repository/grails-core"
}
maven {
url "https://maven.aliyun.com/repository/apache-snapshots"
}
}
}
配置Gradle参数
在/Users/liudong/.gradle文件夹中直接新建一个gradle.properties文件,创建内容不复杂,直接看代码即可,设置Gradle的JVM参数、代理和日志等信息。更多的设置可查看官网。
org.gradle.jvmargs=-Xmx4g -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
systemProp.http.proxyHost=127.0.0.1
systemProp.http.proxyPort=10800
systemProp.https.proxyHost=127.0.0.1
systemProp.https.proxyPort=10800
systemProp.file.encoding=UTF-8
org.gradle.warning.mode=all
myProjectProp=HelloApp
这些属性是可以在buid.gradle.kts中用命令取到的,比如:
if (hasProperty("myProjectProp")) {
// Accessing the value, throws if not present
println(property("myProjectProp"))
}
2.2、Intellij IDEA中创建Gradle项目
OS:MacOS Monterey 12.6.5
idea版本:IntelliJ IDEA 2023.1.1 (Ultimate),不同idea版本截图略有差异。
创建项目
可以【create new project】新建项目,或在已有项目上【create new module】新建模块。建议使用Idea开发时,在源码的管理上可以先创建一个【Empty Project】,然后以module的方式引入源码。这样方便管理,不同的模块也可以有不同的配置方式。下图是在已有项目上创建了一个新模块。
Idea创建模块时所有设置就一个界面,详细解释如下,与构建项目相关的关键信息已标红:
- 语言:项目的开发语言,是什么项目就选什么语言即可;
- 构建系统:必须选择 Gradle;
- JDK:项目的JDK,并不是Gradle依赖的JDK,按项目要求选择相应的版本即可,后续可以在脚本中修改;
- Gradle DSL:Gradle的构建脚本是可编程的,此处是指定Gradle的开发语言,但现在一般的项目都推荐使用Kotlin语言,注意,不同语言生成的构建文件类型不一样,Groovy生成的配置文件以.gradle结尾,选择Kotlin时配置文件以.gradle.kts结尾。
- 父项:相当于maven构建时的parent父项目的意思,后续可以在脚本中修改;
- Gradle分发:选择包装器Gradle Wrapper,后面会着重介绍;
- Gradle版本:默认即可,后续可以在脚本中修改;
- 组ID和工件ID:其实就是类似maven中的groupId和artifactId,后续可以在脚本中修改;
配置好后,点击【创建】会生成如下图所示目录结构:
- .gradle:与gradle相关的支撑缓存文件夹和项目编译等无了,不需要关注。
- gradle:gradle的包装器,下一节会详细说明
- build.gradle:Gradle与项目相关的配置文件,配置项目依赖、打包、插件等,相当于maven的pom.xml文件;
- gradlew:适用于linux和mac系统的Gradle 启动脚本文件;
- gradlew.bat: 适用于windows系统Gradle 启动脚本文件;
- setting.gradle: 添加编译的所有模块;
配置项目
点开IDEA的【首选项】,找到如下图所示的配置页面,按需修改红框内的内容即可:
- Gradle用户主目录:个人习惯是每到一个新公司就设置一个专门的主目录;
- 使用此工具构建和运行:建议改成 Intellij IDEA;
- 使用此工具运行测试:建议改成 Intellij IDEA;
- Gradle JVM:Gradle运行依赖的JDK环境,注意区分不要和项目的JDK弄混;
项目个性化gradle.properties配置
可以项目根路径下同样配置一个名为gradle.properties的文件,大体配置如下:
#性能配置
kotlin.incremental.useClasspathSnapshot = false
kotlin.stdlib.default.dependency = false
org.gradle.configuration-cache = true
org.gradle.caching = true
systemProp.org.gradle.unsafe.kotlin.assignment = true
其它几个常用的配置如下:
- org.gradle.unsafe.configuration-cache = true:开启gradle缓存,加快构建速度
- org.jetbrains.intellij.buildFeature.selfUpdateCheck=false:设置插件是否自动更新检查
- org.jetbrains.intellij.buildFeature.buildSearchableOptions=false:禁止为插件生成索引信息
- org.jetbrains.intellij.buildFeature.paidPluginSearchableOptionsWarning=false:如果插件为付费的,设置是否可搜索;
- kotlin.incremental.useClasspathSnapshot=false:Kotlin 编译器抛出内存不足时的解决方法
- kotlin.stdlib.default.dependency = false:如果Kotlin版本大于1.4设置成false,否则设置成true
- runIde.autoReloadPlugins = true:修改插件后可重新运行build插件,这样就会自动更新了
开发语言配置
java
plugins {
id("java")
}
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
tasks {
withType<JavaCompile> {
sourceCompatibility = "17"
targetCompatibility = "17"
}
}
kotlin
plugins {
id("java")
id("org.jetbrains.kotlin.jvm") version "1.8.21"
}
java {
sourceCompatibility = JavaVersion.VERSION_17
}
tasks {
compileKotlin {
kotlinOptions.jvmTarget = "17"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "17"
}
}
java与kotlin互转
java2kotlin
选择特定的.java文件后,选择菜单栏【code】-【convert java to kotlin】
kotlin2java
选择特定的.kt文件后,选择菜单栏【tool】-【kotlin】-【show kotlin bytecode】,在弹出窗口上选择【反编译】,如下图:
2.3、Gradle Wrapper配置
可以称Gradle Wrapper为Gradle包装器,是将Gradle再次包装。让所有的Gradle构建方法在 Gradle 包装器的帮助下运行。目的是可以让我们不需要在电脑中安装 Gradle 环境也可以运行 Gradle 项目。官方建议任何 Gradle 构建方法在 Gradle Wrapper帮助下运行,利于多人协同开发时环境的统一。
- gradle-wrapper.jar: 既然是 jar 包,那么它肯定是包含了 Gradle 运行时的逻辑代码;
- gradle-wrapper.properties: 这个文件主要负责配置Gradle wrapper运行时的属性文件,声明具体使用哪个版本的 Gradle,详细配置如下:
#Gradle根目录,默认根目录是/Users/userName/.gradle/;
distributionBase=GRADLE_USER_HOME
#distributionBase+distributionPath就是Gradle解包后的存放的具体目录
distributionPath=wrapper/dists
#Gradle项目中用到的Gradle版本,如果你使用IDEA的话推荐下载all版,这样可以分析源代码进而提供更加精确的gradle脚本支持
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip
#Gradle压缩包下载后存储父目录
zipStoreBase=GRADLE_USER_HOME
#zipStoreBase+zipStorePath就是 Gradle 压缩包的存放位置
zipStorePath=wrapper/dists
三、执行Gradle命令
Gradle和Maven一样,有两种执行方式,依拖相关的IDE提供的图形化界面或是命令行;
3.1、IdeaPlugin-UI操作
命令都比较简单,在IDEA右侧选择相应的Gradle项目,所有可执行的命令都在Tasks下面,双击即可。最下面的【运行配置】是一个快捷操作,保存了最近操作过的命令。
3.2、IdeaPlugin-Command操作
3.3、gradleWrapper命令行操作
因为采用的是Gradle Wrapper模式,电脑中并没有安装 Gradle 环境(其实也不建议安装),所以原始的Terminal并没gradle这个命令,需要借助项目根目录下的gradlew(linux和mac) 和 gradlew.bat(windows)文件。首先打开命令行切换到当前项目的根目录下,然后执行相关的命令:./gradlew xxxx 。
3.3、GradleWrapper常用命令
查看版本信息
(base) MacBook:gradleLession liudong$ ./gradlew -v
------------------------------------------------------------
Gradle 8.0
------------------------------------------------------------
Build time: 2023-02-13 13:15:21 UTC
Revision: 62ab9b7c7f884426cf79fbedcf07658b2dbe9e97
Kotlin: 1.8.10
Groovy: 3.0.13
Ant: Apache Ant(TM) version 1.10.11 compiled on July 10 2021
JVM: 1.8.0_144 (Oracle Corporation 25.144-b01)
OS: Mac OS X 10.16 x86_64
查看项目模块
(base) MacBook:gradleLession liudong$ ./gradlew -q projects
------------------------------------------------------------
Root project 'gradleLession'
------------------------------------------------------------
Root project 'gradleLession'
No sub-projects
To see a list of the tasks of a project, run gradlew <project-path>:tasks
For example, try running gradlew :tasks
查看项目依赖列表
(base) MacBook:gradleLession liudong$ ./gradlew dependencies
> Task :dependencies
------------------------------------------------------------
Root project 'gradleLession'
------------------------------------------------------------
annotationProcessor - Annotation processors and their dependencies for source set 'main'.
No dependencies
compileClasspath - Compile classpath for source set 'main'.
+--- org.projectlombok:lombok:1.18.26
\--- mysql:mysql-connector-java:8.0.32
\--- com.mysql:mysql-connector-j:8.0.32
\--- com.google.protobuf:protobuf-java:3.21.9
...省略
A web-based, searchable dependency report is available by adding the --scan option.
BUILD SUCCESSFUL in 531ms
1 actionable task: 1 executed
查看指定构建任务的依赖
./gradlew -q dependencies api:dependencies
./gradlew -q api:dependencies --configuration testCompile
获取特定依赖
gradle -q webapp:dependencyInsight --dependency groovy --configuration compile
org.codehaus.groovy:groovy-all:2.2.0
— project :api
— compile
获取项目属性列表
\> ./gradlew -q api:properties
\------------------------------------------------------------
Project :api - The shared API for the application
\------------------------------------------------------------
allprojects: [project ':api']
ant: org.gradle.api.internal.project.DefaultAntBuilder@12345
antBuilderFactory: org.gradle.api.internal.project.DefaultAntBuilderFactory@12345
artifacts: org.gradle.api.internal.artifacts.dsl.DefaultArtifactHandler@12345
asDynamicObject: org.gradle.api.internal.ExtensibleDynamicObject@12345
buildDir: /home/user/gradle/samples/userguide/tutorial/projectReports/api/build
buildFile: /home/user/gradle/samples/userguide/tutorial/projectReports/api/build.gradle
查看所有任务
(base) MacBook:gradleLession liudong$ ./gradlew task
> Task :tasks
------------------------------------------------------------
Tasks runnable from root project 'gradleLession'
------------------------------------------------------------
Build tasks
-----------
assemble - Assembles the outputs of this project.
build - Assembles and tests this project.
buildDependents - Assembles and tests this project and all projects that depend on it.
buildNeeded - Assembles and tests this project and all projects it depends on.
classes - Assembles main classes.
clean - Deletes the build directory.
jar - Assembles a jar archive containing the main classes.
testClasses - Assembles test classes.
...省略
跳过指定任务
//buid.gradle中定义的Task,mTest
task mTest{
doLast{
println "这是测试Task"
}
}
//在控制台执行命令排除
$ gradle clean build -x mTest
生成构建报告
分析项目构建过程,主要是一些耗时等信息。我们看到控制台它会输出已生成 HTML 格式和 XML 格式的文档。
(base) MacBook:gradleLession liudong$ ./gradlew --profile build
BUILD SUCCESSFUL in 1s
2 actionable tasks: 2 executed
See the profiling report at: file:///Users/liudong/ideaWS/ideaplugin/gradleLession/build/reports/profile/profile-2023-05-12-22-30-15.html
A fine-grained performance profile is available: use the --scan option.
上图中第6行就是生成的报告的地址,也可以在项目根目录下的build/reports/profile目录下找到报告的.html文件,打开后如下图所示:
项目打包
引入打jar包插件
如果想打war包,只面引入以下插件即可:
apply plugin: 'war'
引入打war包插件
如果想打war包,只面引入以下插件即可:
apply plugin: 'war'
打包
编译并打包 jar 文件,但不会执行单元测试,用的是assemble命令。一些其他插件可能会增强这个任务的功能。例如,如果采用了 War 插件,这个任务便会为你的项目打出 War 包。
// 编译并打Debug包
$ gradle assembleDebug
// 编译app module 并打Debug包
$ gradlew install app:assembleDebug
// 编译并打Release的包
# gradle assembleRelease
// 编译并打Release包并安装
$ gradle installRelease
// 卸载Release包
$ gradle uninstallRelease
指定main.class
指定应用是一个app,然后指定Hello为main.java。
plugins {
id("application")
}
application {
mainClass.set("com.example.Hello")
}
把依赖打到jar包中
tasks {
// 将依赖打进jar包中
jar.configure {
duplicatesStrategy = org.gradle.api.file.DuplicatesStrategy.INCLUDE
from(configurations.runtimeClasspath.get().filter { it.name.endsWith("jar")}.map { zipTree(it) })
}
}
私服发布
需要修改build.gradle文件,详细代码如下,然后执行右侧 publishing 命令。
plugins {
id 'java-library'
id 'maven-publish'
}
publishing {
publications {
myLibrary(MavenPublication) {
from components.java
}
}
repositories {
maven {
// default credentials for a nexus repository manager
credentials {
username 'admin'
password 'xxxxx'
}
allowInsecureProtocol = true //允许http
// 发布maven存储库的url
url "http://localhost:8080/nexus/content/repositories/releases/"
}
}
}
其它常用命令参数
gradle -Dorg.gradle.logging.level=warn clean
-Dorg.gradle.logging.level=(quiet,warn,lifecycle,info,debug)
四、Gradle的生命周期
gradle 构建的生命周期主要分为三个阶段,Initialization,Configuration,Execution。
- Initialization:Gradle支持单个或多个工程的构建。在Initialization阶段,Gradle决定哪些工程将参与到当前构建过程,并为每一个这样的工程创建一个Project实例。一般情况下,参与构建的工程信息将在settings.gradle中定义。
- Configuration:在这一阶段,配置project的实例。所有工程的构建脚本都将被执行。Task,configuration和许多其他的对象将被创建和配置。
- Execution:在之前的configuration阶段,task的一个子集被创建并配置。这些子集来自于作为参数传入gradle命令的task名字,在execution阶段,这一子集将被依次执行。
五、依赖管理
大体的配置如下所示:
plugins {
id 'org.springframework.boot' version '2.7.4'
id 'java'
}
group = 'com.zd'
version = '1.0-SNAPSHOT'
repositories {
mavenLocal()
maven { url "https://maven.aliyun.com/nexus/content/repositories/central/" }
mavenCentral()
}
dependencies {
testImplementation 'junit:junit:4.13'
implementation 'org.projectlombok:lombok:1.18.26'
implementation 'mysql:mysql-connector-java:8.0.32'
}
buildscript {
ext {
springBootVersion = "2.3.3.RELEASE"
}
repositories {
mavenLocal()
maven { url 'http://maven.aliyun.com/nexus/content/groups/public' }
jcenter()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
项目配置
和发布打包相关的一些配置。
group = 'com.zd'
version = '1.0-SNAPSHOT'
插件配置
gradle插件类似于maven插件,plugins闭包(标签)里的插件必须是gradle官方插件库(http://plugins.gradle.org)里的,另外plugins块不能放在多项目配置块(allProjects, subProjects)里。另外因为java是核心插件,所以不用指定版本,而其它的插件比如org.springframework.boot是社区插件,所以必须指定版本。
plugins {
id 'org.springframework.boot' version '2.7.4'
id 'java'
}
buildscript配置
buildscript中的声明是gradle脚本自身需要使用的资源。可以声明的资源包括依赖项、第三方插件、maven仓库地址等。而在build.gradle文件中直接声明的依赖项、仓库地址等信息是项目自身需要的资源。gradle在执行脚本时,会优先执行buildscript代码块中的内容,然后才会执行剩余的build脚本。
buildscript代码块中的repositories和dependencies的使用方式与直接在build.gradle文件中的使用方式几乎完全一样。唯一不同之处是在buildscript代码块中你可以对dependencies使用classpath声明。该classpath声明说明了在执行其余的build脚本时,class loader可以使用这些你提供的依赖项。这也正是我们使用buildscript代码块的目的。某种意义上来说,classpath 声明的依赖,不会编译到最终的jar包里面
另外,buildscript必须位于plugins块和apply plugin之前
buildscript {
ext {
springBootVersion = "2.3.3.RELEASE"
}
repositories {
mavenLocal()
maven { url 'http://maven.aliyun.com/nexus/content/groups/public' }
jcenter()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
注意上面代码中的ext代码块,ext代码块是提供给用户自定义属性用的,一般用来定义版本,实现版本的集中管理。
仓库配置
gradle仓库可以直接使用maven的仓库,但是gradle下载的jar包文件格式与maven不一样,所以不能和maven本地仓库共用,仓库的配置,是在repository中的:
repositories {
mavenLocal() //本地仓库
maven { url 'http://maven.aliyun.com/nexus/content/groups/public' } //外部仓库(阿里云)
mavenCentral() // maven 中心仓库
}
jar依赖配置
gradle依赖写在dependcies代码块中,gradle中引入依赖只需要一行,遵循scope 'gropId:artifactId:version'
的格式,也可以是scope (gropId:artifactId:version)
dependencies {
testImplementation 'junit:junit:4.13'
implementation 'org.projectlombok:lombok:1.18.26'
implementation 'mysql:mysql-connector-java:8.0.32'
}
dependencies {
testImplementation('junit:junit:4.13')
implementation('org.projectlombok:lombok:1.18.26')
implementation('mysql:mysql-connector-java:8.0.32')
}
maven只有compile、provided、test、runtime,而gradle有以下几种scope:
- implementation:默认的scope,会将指定的依赖添加到编译路径,并且会将该依赖打包到输出,但是这个依赖在编译时不能暴露给其他模块,例如如果我们的类库包含了gson,那么其他人使用我们的类库时,编译时不会出现gson的依赖。
- api:api关键字是由java-library提供,若要使用,请在plugins中添加:
id 'java-library'
== (在旧版本中作用与compile相同,新版本移除了compile)使用api配置的依赖会将对应的依赖添加到编译路径,并将依赖打包输出,但是这个依赖是可以传递的,比如模块A依赖模块B,B依赖库C,模块B在编译时能够访问到库C,但是与implemetation不同的是,在模块A中库C也是可以访问的。 - compileOnly:compileOnly修饰的依赖会添加到编译路径中,但是不会被打包,因此只能在编译时访问,且compileOnly修饰的依赖不会传递。
- runtimeOnly:这个与compileOnly相反,它修饰的依赖不会添加到编译路径中,但是能被打包,在运行时使用。和Maven的provided比较接近。
- annotationProcessor:用于注解处理器的依赖配置。
- testImplementation:这种依赖在测试编译时和运行时可见,类似于Maven的test作用域。
- testCompileOnly和testRuntimeOnly:这两种类似于compileOnly和runtimeOnly,但是作用于测试编译时和运行时。
- classpath:见上一段,classpath并不能在buildscript外的dependcies中使用
排除依赖包中的依赖
我们开发中,可能大家或多或少都会遇到 jar 包冲突的问题,有时候两个 jar 包不同,但是里面有两个类的包名路径是一摸一样的。这样我们就需要排除掉某个包中的重复的类,这时候就需要用的 exclude 命令,如下例子:
compile('org.hibernate:hibernate:3.1') {
//以artifact name来排除出
exclude module: 'cglib'
//通过group name来排除
exclude group: 'org.jmock'
}
排除环境依赖
configurations {
runtime.exclude group: "org.slf4j", module: "slf4j-log4j12"
compile.exclude group: "org.slf4j", module: "slf4j-log4j12"
}
全局排除依赖
configurations.all {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
}
六、多模块项目搭建
6.1、项目搭建
新建父工程
按下图创建一个新的项目,注意要选择【新建项目】,然后删除项目中的src文件夹。
新建子模块
如下图所示,注意下图中的父项要选b2bdemo。
经过以上两部后,项目的目录情况如下图所示:
项目工程设置
统一由settings.gradle文件管理,配置文件如下所示,其它文件没有特殊的地方,注意groovy和kts的写法,一般就是差个(),然后把'改成":
rootProject.name = 'b2bdemo'
include 'api'
include 'server'
rootProject.name = "b2bdemo"
include("api")
另外可以有更多的配置管理,比如:
include("project-a")
project(":project-a").projectDir = file("../my-project-a")
project(":project-a").buildFileName = "project-a.gradle"
6.2、父工程配置
build.gradle配置
allprojects{ // 所有模块的配置
group = 'org.example'
version = '0.0.1'
repositories {
mavenLocal()
maven { url 'https://maven.aliyun.com/repository/public/' }
mavenCentral()
}
//指定编码格式
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
}
//这里的clean它是一个 Gradle 任务,它继承自Delete,执行clean命令时删除build文件夹下的内容。
task clean(type: Delete) {
delete rootProject.buildDir
}
}
subprojects { //子模块配置
apply plugin: "java"
apply plugin: 'java-library'
apply plugin: "idea" //指定编辑器
//java版本
sourceCompatibility = 1.8
targetCompatibility = 1.8
//公共依赖
dependencies {
compileOnly 'org.projectlombok:lombok:1.18.20'
annotationProcessor 'org.projectlombok:lombok:1.18.20'
}
}
多模块依赖管理
在7.0+版本,gradle提供了dependencyResolutionManagement来进行多模块之间的依赖共享,类似于maven的dependencyManagement:
第一步:
在7.4以下版本启用该功能,得在
settings.gradle
中添加enableFeaturePreview('VERSION_CATALOGS')
,在settings.gradle
中添加:
dependencyResolutionManagement{
versionCatalogs{
libs{ //libs名字可以任意取,最好为libs,到8.0可能会强制使用libs
library('hutool-core','cn.hutool:hutool-core:5.8.6')
//library在7.4以下版本为alias在7.4+版本被弃用,并且alias用法与library略有区别,详情参考文末链接
}
}
}
library第一个字符串为依赖的别名,注意别名必须由一系列以破折号(-
,推荐)、下划线 (_
) 或点 (.
) 分隔的标识符组成(当然,不写分隔符也可以)。标识符本身必须由ascii
字符组成,最好是小写,最后是数字。
第二步:
之后,便可以在子模块build.gradle中使用:
dependencies {
implementation(libs.hutool.core)
}
同版本参数设置
如果几个依赖共用一个版本,可以使用version来统一管理版本(注意,library中groupid与artifactid用‘,’隔开了),dependencies中用法一致
dependencyResolutionManagement{
versionCatalogs{
libs{
version('hutool','5.8.6')
library('hutool-core','cn.hutool','hutool-core').versionRef('hutool')
library('hutool-http','cn.hutool','hutool-http').versionRef('hutool')
library('hutool-json','cn.hutool','hutool-json').versionRef('hutool')
}
}
}
依赖批量引入
要是不想一个个引用这几依赖的话,还可以使用bundles将几个依赖绑定到一起,一次性引入多个依赖:
dependencyResolutionManagement{
versionCatalogs{
libs{
version('hutool','5.8.6')
library('hutool-core','cn.hutool','hutool-core').versionRef('hutool')
library('hutool-http','cn.hutool','hutool-http').versionRef('hutool')
library('hutool-json','cn.hutool','hutool-json').versionRef('hutool')
bundle('hutool',['hutool-core','hutool-http','hutool-json'])
}
}
}
在子模块的build.gradle中的dependencies中:
dependencies {
implementation(libs.bundles.hutool)
}
插件共享
dependencyResolutionManagement{
versionCatalogs{
libs{
plugin('spring-dependency','io.spring.dependency-management').version('1.0.14.RELEASE')
}
}
}
6.3、模块之间的运行依赖
只需要在dependencies中按照如下格式依赖即可,并且也是遵循依赖引入的几种scope规则的,要注意的是,被引用项目的类必须在软件包下,才可以被找到,下例代码中的:server为一个项目模块。
dependencies {
testImplementation platform('org.junit:junit-bom:5.9.1')
testImplementation 'org.junit.jupiter:junit-jupiter'
implementation(':server')
}
implementation(project(":server"))
6.4、模块间的构建依赖
在setting.gradle.kts中配置,
rootProject.name = "my-composite"
includeBuild("my-app")
includeBuild("my-utils")
然后在子模块中配置task,这样在构建子模块之前会先执行模块my-app的任务。
tasks.register("run") {
dependsOn(gradle.includedBuild("my-app").task(":app:run"))
}
七、自定义Task
一般定义在build.gradlw.kts文件中。详细参考文件处理
7.1、定义简单任务
自定义的任务会显示在idea右侧工具栏的other标签中,双击就可以运行。
tasks.register("testBoth") {
doFirst {
println("This is executed first during the execution phase.")
}
doLast {
println("This is executed last during the execution phase.")
}
println("This is executed during the configuration phase as well, because :testBoth is used in the build.")
}
//gradle -q testBoth
执行顺序是 println, first, last, -q表示不打印日志
7.2、使用预置好的任务
这里的Copy是Gradle插件带的一些快捷工具,下面代码表示使用Copy工具定义一个名为copyReportsDirForArchiving的任务,复制文件。类似的还有zip、delete等。
tasks.register<Copy>("copyReportsDirForArchiving") {
from(layout.buildDirectory.dir("reports"))
into(layout.buildDirectory.dir("toArchive"))
}
7.3、复写当前任务
tasks.register<Delete>("cleanOutDir") {
dependsOn(":clean")
delete(rootProject.buildDir.path + "/../out")
}
7.4、模块间任务共享
// demo.gradle
task showProjectName{
doLast {
println("$project.name")
}
}
showProjectName.enabled = false//禁用任务
// demo1.gradle
apply from: '../demo.gradle'
//运行,使用任务全拼
$ gradle showProjectName
八、常见问题
gradle lombok找不到符号?
一般在build.gradle.kts中做如下配置,同时检查下Gradle配置
compileOnly("org.projectlombok:lombok:1.18.26")
annotationProcessor("org.projectlombok:lombok:1.18.26")
testCompileOnly("org.projectlombok:lombok:1.18.26")
testAnnotationProcessor("org.projectlombok:lombok:1.18.26")
如果还不行再检查下以下配置(正常来讲不需要做如下的改动,具体原因没查,需要试):
- File => Settings => Build, Execution, Deployment => Compiler => Annotation Processors => Enable annotation processing
- 调整编译器:由javac >> Eclipse,启用方法:File => Settings => Build, Execution, Deployment => Compiler => Java Compiler =>Use compiler Eclipse
- 在项目的根目录下面,添加如下内容的:lombok.config文件
# lombok.config
# 声明该配置文件是一个根配置文件,从该配置文件所在的目录开始扫描
config.stopBubbling=true
# 全局配置 equalsAndHashCode 的 callSuper 属性为true
lombok.equalsAndHashCode.callSuper=call
- 部署在jenkins上面需要注释掉: annotationProcessor和testAnnotationProcessor