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

  • 速度: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这两个文件,需要手动添加,这两个文件就是全局配置文件。但建议每到一个公司就修改一个目录(习惯问题,可按个人习惯决定是否分开)

Gradle构建工具中文教程_maven_02

  • 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的方式引入源码。这样方便管理,不同的模块也可以有不同的配置方式。下图是在已有项目上创建了一个新模块。

Gradle构建工具中文教程_maven_03

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构建工具中文教程_maven_04

  • .gradle:与gradle相关的支撑缓存文件夹和项目编译等无了,不需要关注。
  • gradle:gradle的包装器,下一节会详细说明
  • build.gradle:Gradle与项目相关的配置文件,配置项目依赖、打包、插件等,相当于maven的pom.xml文件;
  • gradlew:适用于linux和mac系统的Gradle 启动脚本文件;
  • gradlew.bat: 适用于windows系统Gradle 启动脚本文件;
  • setting.gradle: 添加编译的所有模块;

配置项目

点开IDEA的【首选项】,找到如下图所示的配置页面,按需修改红框内的内容即可:

Gradle构建工具中文教程_Gradle_05

  • 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】,在弹出窗口上选择【反编译】,如下图:

Gradle构建工具中文教程_Gradle_06

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操作

Gradle构建工具中文教程_maven_07

命令都比较简单,在IDEA右侧选择相应的Gradle项目,所有可执行的命令都在Tasks下面,双击即可。最下面的【运行配置】是一个快捷操作,保存了最近操作过的命令。


3.2、IdeaPlugin-Command操作

Gradle构建工具中文教程_maven_08

3.3、gradleWrapper命令行操作

因为采用的是Gradle Wrapper模式,电脑中并没有安装 Gradle 环境(其实也不建议安装),所以原始的Terminal并没gradle这个命令,需要借助项目根目录下的gradlew(linux和mac) 和 gradlew.bat(windows)文件。首先打开命令行切换到当前项目的根目录下,然后执行相关的命令:./gradlew xxxx  。

Gradle构建工具中文教程_maven_09

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文件,打开后如下图所示:

Gradle构建工具中文教程_Gradle_10

项目打包

引入打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文件夹

Gradle构建工具中文教程_Gradle_11

新建子模块

如下图所示,注意下图中的父项要选b2bdemo。

Gradle构建工具中文教程_Gradle_12

经过以上两部后,项目的目录情况如下图所示:

Gradle构建工具中文教程_Gradle_13

Gradle构建工具中文教程_Gradle_14

项目工程设置

      统一由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")

Gradle构建工具中文教程_Gradle_15

如果还不行再检查下以下配置(正常来讲不需要做如下的改动,具体原因没查,需要试):

  • 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