项目构建之Gradle
Gradle
Gradle 是一款基于 Apache Ant 和 Apache Maven 的项目自动化构建工具。Gradle 构建脚本使用的是基于 Groovy 或 Kotlin 的领域特定语言(DSL)来编写的,而不是传统的 XML。
Gradle 是Android 的官方构建工具,并且支持多种主流语言的构建:Java、Android 、C++、Groovy 、Kotlin、JS。

Gradle VS Maven
Maven 和 Gradle 都是项目构建工具,二者的主要区别是什么呢?Gradle 更有优势的方面,一是基于Groovy语言的语法更加简洁,二是控制更灵活,一些在Maven中难以下手的事情,在Gradle中就比较容易实现。
相比于Gradle的不灵活,也正是Maven 的优点,因为XML的标准化配置让使用者很容易上手。借用网友的一句话:“自由有自由的代价,标准有标准的好处”。Maven更加的标准和规范,Gradle更加的灵活和高效,Gradle 和 Maven 在实际开发中都很常用。
配置文件
几个配置文件:
build.gradle 构建脚本
settings.gradle 设置脚本
gradle.properties 全局属性文件(非必须)
常用选项:
-v //查看版本
-h //查看帮助
-D //设置JVM系统参数
-c, --settings-file //指定设置文件
-b, --build-file //指定构建文件
-x, --exclude-task //指定要排除的任务
-s, --stacktrace //打印出所有异常的堆栈跟踪。
--refresh-dependencies //刷新依赖
-d, --debug //debug 输出
--no-build-cache //禁用Gradle 构建缓存。
--build-cache //启用 Gradle 构建缓存。 Gradle 将尝试重用以前构建的输出。
--no-daemon //不使用 Gradle 守护进程来运行构建。
-q //仅打印错误日志
注:在执行gradle命令时,使用-D加参数与在gradle.properties 文件中加参数是一样的效果。
属性参数
Gradle最终的参数配置是命令行参数和 gradle.properties
文件中定义的属性参数的整合,如果一个参数在多个地方进行了定义配置,那么将会按以下的顺序从上往下顺序,第一个出现的配置为准:
- 命令行中通过
-P
或者--project-prop
配置的变量参数; - Gradle用户目录(
GRADLE_USER_HOME
)中gradle.properties
文件中定义的属性; - 项目根目录中
gradle.properties
文件中定义的属性;
注意事项:
- Gradle参数配置中,命令行传入的参数具有最高优先级;
- 整个体系会存在多个
gradle.properties
文件,根据优先级查找属性配置,如果配置的属性不生效,请检查更高优先级的gradle.properties
文件中是否也存在同样的属性配置;
常用属性:
org.gradle.parallel=(true,false)
是否开启并行构建。如果设置为true
,Gradle 将会以org.gradle.workers.max
参数指定数量的 JVM 并行执行项目的并行构建。默认值是false
。org.gradle.workers.max=(max # of worker processes)
设置 Gradle 最大工作线程数,设置之后,Gradle 会根据给定的最大工作线程数并行构建项目。默认值是当前设备 CPU 的线程数。org.gradle.caching=(true,false)
构建缓存配置。当设置为 true 时,Gradle会尽可能复用任何之前构建的任务输出,可以大大提高构建速度。默认值为 false(禁用构建缓存)。org.gradle.caching.debug=(true,false)
构建缓存调试开关。当设置为 true 时,部分输入属性的哈希值和构建缓存中的每一个任务的缓存 key 将会在控制台中输出。默认为 false。org.gradle.daemon=(true,false)
启用守护进程,如果设置为 true,Gradle将会启动守护进程运行构建,默认值为 true。org.gradle.daemon.idletimeout=(# of idle millis)
守护进程空闲时间上限,如果Gradle守护进程空闲时间超过这个上限,守护进程将会自己关闭。默认值是 10800000 毫秒(3小时)。org.gradle.java.home=(path to JDK home)
指定Java根目录。为Gradle构建进程指定一个Java主目录,这个值可以设置为 JDK 或者 jar 所在的目录路径(取决于你构建的内容,使用JDK更安全)。这个属性配置不会影响启动 Gradle 客户端VM的 Java 版本(仅影响当前的 Gradle 构建)。如果没有指定,正常情况下默认值是在系统环境变量中 JAVA_HOME 指定或者指向 Java 的路径。org.gradle.jvmargs=(JVM arguments)
设置 JVM参数。指定用于 Gradle 守护进程使用的 JVM 参数。这个参数设置仅仅作用与 Gradle 构建的 JVM 内存配置,并不会影响 Gradle 客户端运行的 JVM 设置。默认值是 -Xmx512m “-XX:MaxMetaspaceSize=256m”。org.gradle.logging.level=(quiet,warn,lifecycle,info,debug)
指定日志输出级别。Gradle会使用指定的日志输出级别,不同的级别将会影响日志输出结果和详细情况。默认值是 lifecycle。org.gradle.warning.mode=(all,fail,summary,none)
设置 Gradle 警告展示级别,Gradle 会根据不同值展示不同级别类型的警告信息。默认值是summary
。
环境变量相关
在 Gradle 中,支持的环境变量有以下几个:
GRADLE_USER_HOME
用来指定 Gradle 用户目录(Gradle用户目录默认值为$USER_HOME/.gradle
)。JAVA_HOME
用来指定客户端 VM 使用的 JDK 所在的安装目录,这个客户端 VM 也用于守护进程(一般配置JDK环境的时候都会配置此环境变量)。如果在 gradle.properties 文件中 使用 org.gradle.java.home 属性配置了不同的目录,将会忽略此环境变量配置。
Project API
项目和 build.gradle 文件之间存在一对一的关系。 在构建初始化期间,Gradle 为每个要参与构建的项目组装一个 Project 对象。
- 在构建脚本中,你所调用的任何一个方法,如果在构建脚本中未定义,它将被委托给 Project 对象。
- 在构建脚本中,你所访问的任何一个属性,如果在构建脚本里未定义,它也会被委托给 Project 对象。
访问 Project 对象的属性
build.gradle
println name
println project.name
这两个 println 语句打印出相同的属性。在生成脚本中未定义的属性,第一次使用时自动委托到 Project 对象。
标准 project 属性
Project对象提供了一些在构建脚本中可用的标准的属性。
Property | Description |
---|---|
allprojects |
包含该项目及其子项目的集合。 |
ant |
该项目的“AntBuilder”。 您可以在构建文件中使用它来执行 ant 任务。 |
artifacts |
返回一个处理程序,用于将项目生成的工件分配给配置。 |
buildDir |
该项目的构建目录。 构建目录是生成所有工件的目录。 构建目录的默认值为*projectDir*/build |
buildFile |
该项目的构建脚本。 |
buildscript |
该项目的构建脚本处理程序。 您可以使用此处理程序来查询有关该项目的构建脚本的详细信息,并管理用于编译和执行项目的构建脚本的类路径。 |
childProjects |
该项目的直接子项。 |
configurations |
该项目的配置。 |
convention |
deprecatedThe Convention for this project. |
defaultTasks |
该项目的默认任务的名称。 当开始构建时未提供任务名称时,将使用这些任务。 |
dependencies |
该项目的依赖处理程序。 返回的依赖项处理程序实例可用于添加新的依赖项。 为了访问已经声明的依赖项,可以使用配置。 |
dependencyLocking |
Provides access to configuring dependency locking |
description |
该项目的描述(如果有)。 |
extensions |
Allows adding DSL extensions to the project. Useful for plugin authors. |
gradle |
The Gradle invocation which this project belongs to. |
group |
这个项目的小组。 Gradle 始终使用该组的“toString()”值。 该组默认为以点作为分隔符的路径。 |
logger |
该项目的记录器。 您可以在构建文件中使用它来写入日志消息。 |
logging |
The LoggingManager which can be used to receive logging and to control the standard output/error capture for this project’s build script. By default, System.out is redirected to the Gradle logging system at the QUIET log level, and System.err is redirected at the ERROR log level. |
name |
这个项目的名称。 项目的名称在项目层次结构中不一定是唯一的。 您应该使用 [Project.getPath() ] 方法来获取项目的唯一标识符。 |
normalization |
Provides access to configuring input normalization. |
parent |
该项目的父项目(如果有)。 |
path |
该项目的路径。 该路径是项目的完全限定名称。 |
pluginManager |
The plugin manager for this plugin aware object. |
plugins |
已应用于此对象的插件的容器。 |
project |
返回该项目。 此方法在构建文件中非常有用,可显式访问项目属性和方法。 例如,使用“project.name”比使用“name”更能表达您的意图。 此方法还允许您从可能隐藏属性的范围(例如从方法或闭包)访问项目属性。 |
projectDir |
包含项目构建文件的目录。 |
properties |
该项目的属性。 |
repositories |
返回一个处理程序来创建存储库,该存储库用于检索依赖项并上传项目生成的工件。 |
resources |
Provides access to resource-specific utility methods, for example factory methods that create various resources. |
rootDir |
The root directory of this project. The root directory is the project directory of the root project. |
rootProject |
The root project for the hierarchy that this project belongs to. In the case of a single-project build, this method returns this project. |
state |
The evaluation state of this project. You can use this to access information about the evaluation of this project, such as whether it has failed. |
status |
The status of this project. Gradle always uses the toString() value of the status. The status defaults to release . |
subprojects |
包含该项目的子项目的集合。 |
tasks |
本项目的任务。 |
version |
该项目的版本。 Gradle 始终使用版本的“toString()”值。 版本默认为“未指定”。 |
插件添加的project属性
java plugin 添加的属性
Property | Description |
---|---|
archivesBaseName |
The base name to use for archive files. |
base |
The BasePluginExtension added by the java plugin. |
distsDirName |
The name for the distributions directory. This in interpreted relative to the project’ build directory. |
distsDirectory |
The directory to generate TAR and ZIP archives into. |
docsDir |
Returns a file pointing to the root directory supposed to be used for all docs. |
docsDirName |
The name of the docs directory. Can be a name or a path relative to the build dir. |
java |
The JavaPluginExtension added by the java plugin. |
libsDirName |
The name for the libs directory. This in interpreted relative to the project’ build directory. |
libsDirectory |
The directory to generate JAR and WAR archives into. |
reporting |
The ReportingExtension added by the java plugin. |
sourceCompatibility |
The source compatibility used for compiling Java sources. |
sourceSets |
The source sets container. |
targetCompatibility |
The target compatibility used for compiling Java sources. |
testReportDir |
Returns a file pointing to the root directory to be used for reports. |
testReportDirName |
The name of the test reports directory. Can be a name or a path relative to ReportingExtension.getBaseDir() . |
testResultsDir |
Returns a file pointing to the root directory of the test results. |
testResultsDirName |
The name of the test results directory. Can be a name or a path relative to the build dir. |
publishing plugin 添加的属性
Property | Description |
---|---|
publishing |
The PublishingExtension added by the publishing plugin. |
idea plugin 添加的属性
Property | Description |
---|---|
idea |
The IdeaModel added by the idea plugin. |
eclipse plugin 添加的属性
Property | Description |
---|---|
eclipse |
The EclipseModel added by the eclipse plugin. |
Project 方法
Methods
方法 | 说明 |
---|---|
apply(closure) |
应用零个或多个插件或脚本。 |
configure(objects, configureClosure) |
配置gradle对象 |
task(name, configureClosure) |
创建一个任务 |
Script API
当 Gradle 执行一个脚本时,它将脚本编译为一个实现了 Script 接口的类。这意味着所有由该Script 接口声明的属性和方法在您的脚本中是可用的。
声明变量
有两类可以在生成脚本中声明的变量: 局部变量和额外属性。
局部变量
局部变量是用 def
关键字声明的。它们只在定义它们的范围内可以被访问。局部变量是 Groovy 语言底层的一个特征。
def dest = "dest"
task copy(type: Copy) {
from "source"
into dest
}
额外属性
Gradle 中,所有增强的对象都可以容纳用户定义的额外的属性。这包括但并不限于项目(project)、任务(task)和源码集(source set)。额外的属性可以通过所属对象的 ext 属性进行添加,读取和设置。或者,可以使用 ext 块同时添加多个属性。
apply plugin: "java"
ext {
springVersion = "3.1.0.RELEASE"
emailNotification = "build@master.org"
}
sourceSets.all { ext.purpose = null }
sourceSets {
main {
purpose = "production"
}
test {
purpose = "test"
}
plugin {
purpose = "production"
}
}
task printProperties << {
println springVersion
println emailNotification
sourceSets.matching { it.purpose == "production" }.each { println it.name }
}
在此示例中, 一个 ext 代码块将两个额外属性添加到 project 对象中。此外,通过将ext.purpose 设置为 null(null是一个允许的值),一个名为 purpose 的属性被添加到每个源码集(source set)。一旦属性被添加,他们就可以像预定的属性一样被读取和设置。
构建日志
--profile
参数可以收集一些构建期间的信息并保存到 build/reports/profile 目录下并且以构建时间命名这些文件。
声明依赖项
指定仓库位置
gradle 会根据 repositories 中声明的仓库顺序,依次寻找程序包。
//指定仓库位置
repositories {
mavenCentral()
}
配置多个仓库:
repositories {
mavenLocal()
maven {
url "http://jackpot.com.cn/nexus/repository/maven-nr-public/"
credentials {
username nexusUsername
password nexusPassword
}
}
maven { url "http://maven.aliyun.com/nexus/content/groups/public/" }
maven { url "https://repo.spring.io/snapshot" }
maven { url "https://repo.spring.io/milestone" }
mavenCentral()
}
上面的例子,依次从本地maven仓库、公司私服maven仓库、阿里云仓库、Spring快照仓库、Spring里程碑仓库、Maven中央仓库中寻找。
gradle 只会读取maven仓库中的资源(jar包),而不会往里写入资源。换句话说,如果在本地maven仓库中找不到,那么在其他远程仓库下载的jar包不会存放到本地maven仓库中,而是放到自己的缓存目录下。
声明依赖
在 Gradle 3.4 及以下版本,我们引入依赖的方式通过 compile
:
//声明依赖
dependencies {
compile "joda-time:joda-time:2.2"
compile project(':common:util')
testCompile "junit:junit:4.12"
}
从左到右依次是 group、name、version 标识,中间使用英文冒号隔开。
到 Gradle 3.4+ 之后,Gradle 支持了默认的新的引入依赖的方式: implementation
:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
Gradle 中的 compile
配置在 Gradle 4.6 版本中被废弃,并在 Gradle 7.0 版本中正式移除了。这个变更是Gradle 4.x 系列引入的一系列变更中的一部分,旨在改进依赖配置的可读性和语义。
在 Gradle 中,compile
配置用于指定在编译代码时所需的依赖项。然而,由于 compile
这个词在语义上不够清晰(它可以被解释为编译时依赖和运行时依赖),Gradle 团队决定将其拆分为更明确的配置:implementation
、api
和 runtimeOnly
。
implementation
:用于指定在编译代码时所需的依赖项。这些依赖项不会暴露给模块的消费者。这是compile
配置的直接替代品。api
:类似于implementation
,但这些依赖项会暴露给模块的消费者。这是为了兼容旧版本的compile
配置。runtimeOnly
:用于指定仅在运行时所需的依赖项。这些依赖项不会用于编译代码。
Gradle 团队建议开发者在项目中使用新的依赖配置(implementation
、api
和 runtimeOnly
),因为它们更具有语义明确性,并且可以更好地描述依赖项在构建中的角色。
Gradle 中的 testRuntime
依赖配置是从 Gradle 4.6 版本开始废弃的,并在 Gradle 6.0 版本中正式移除了。Gradle 团队建议您使用 testImplementation
配置来代替 testRuntime
。
使用 api 的前提是 确保在 build.gradle
文件中应用了 java-library
插件:
plugins {
id 'java-library'
}
dependencies {
api 'org.apache.commons:commons-lang3:3.12.0'
implementation 'com.google.guava:guava:30.1.1-jre'
}
引入Pom依赖:
dependencyManagement {
imports {
mavenBom "org.springframework.statemachine:spring-statemachine-bom:${springStatemachineVersion}"
}
}
dependencies {
api platform("org.springframework:spring-framework-bom:$springFrameworkVersion")
api platform("com.fasterxml.jackson:jackson-bom:2.14.2")
constraints {
api "ch.qos.logback:logback-classic:1.4.6"
api "com.google.inject:guice:3.0"
}
optional 'com.fasterxml.jackson.core:jackson-databind'
}
api
关键字表示这些依赖是需要在编译时和运行时都使用的,因此这些依赖将被包含在项目的 JAR 文件中。
platform
关键字用于声明一个平台(Platform),而 spring-framework-bom
则是平台的名称。这个平台由 Spring Framework 的 BOM(Bill of Materials)文件提供,它定义了一组 Spring Framework 相关的依赖版本,用于保证这些依赖版本的兼容性。$springFrameworkVersion
是一个变量,用于指定 Spring Framework 的版本号,通常在文件中进行定义。这个变量将被替换为实际的版本号,例如 5.3.9
。
constraints
指令是使用 Gradle 7.x 中的新特性:dependency constraints(依赖约束)。它的作用是用于解决依赖冲突的问题,保证构建时使用的依赖版本是一致的。在这里,它表示使用 logback-classic
的版本必须是 1.4.6
,如果其它依赖使用了不同版本的 logback-classic
,则会被 Gradle 强制解析为 1.4.6
版本。这可以避免因依赖冲突导致的构建错误和运行时异常。
optional
也是声明依赖,与api的区别在于它的声明是可选的,不是强制依赖,如果存在则获取,否则不获取。
api
和 implementation
区别
在 Gradle 的依赖管理中,api
和 implementation
都是用来定义项目中的依赖关系的关键字。
api
: 定义的依赖关系是公共 API,如果一个项目A中使用了一个API,那么项目B引用项目A时,也能访问到这个API。换句话说,使用api
声明的依赖关系不仅会被编译到当前项目中,还会被传递到依赖该项目的项目中。在插件中使用api
,则表示向插件的使用者公开插件的 API。implementation
: 定义的依赖关系是私有的,只在当前项目内可见。使用implementation
声明的依赖关系不会被传递到依赖该项目的项目中。这意味着依赖库的 API 只能在当前项目内使用,不能在其他项目中访问。
因此,如果一个库只在当前项目中使用,应该使用 implementation
,以保证不会将其 API 传递到其他项目中。如果一个库的 API 要被其他项目使用,应该使用 api
。
需要注意的是,这两个关键字是在 Gradle 3.4 引入的,如果使用的 Gradle 版本较低,可能需要使用 compile
和 provided
代替 implementation
和 api
。
排除依赖
两种方式排除某个依赖中的模块:
- 通过 configuration 全局配置
- 在依赖声明中 dependencies 添加
exclude
的方式来排除指定的引用
想要移除掉某个依赖中的模块,我们通常会这么做:(Gradle 3.4 及以下版本)
dependencies {
compile('commons-beanutils:commons-beanutils:1.9.4') {
// 指定group 和 module
exclude group: 'commons-collections', module: 'commons-collections'
}
// 指定group 但不指定 module
compile('commons-beanutils:commons-beanutils:1.9.4') {
exclude group: 'commons-collections'
}
}
Gradle 3.4+ 之后:
dependencies {
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
全局排除指定环境的依赖:
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'
}
使用强制版本
我们在开发的过程当中,会依赖使用各种第三方库,比如说最常见的 appcompat-v7
库,不仅我们自己的代码里会依赖该库,而且有可能我们依赖的第三方库也会依赖该库,但是不同的地方依赖该库的版本号都有可能不一致,这样在编译的时候,整个项目当中会出现各种不同版本号的 appcompat-v7
库,编译的时候可能会报错。我们不可能修改第三方库里对 appcompat-v7
库依赖的版本号,那么我们可以通过 resolutionStrategy.force
来强制编译时统一库的版本号。
android {
configurations.all {
resolutionStrategy {
force 'com.android.support:appcompat-v7:28.0.0'
}
}
}
全局配置强制使用某个版本的依赖来解决依赖冲突中出现的依赖
configurations.all {
resolutionStrategy {
force 'org.hamcrest:hamcrest-core:1.3'
}
}
或者指定force = true
属性可以冲突时优先使用该版本进行解决。
compile('org.hibernate:hibernate:3.1') {
force = true
}
constraints
和 force
区别
在 Gradle 中,constraints
和 force
都是用来约束依赖版本的关键字,但是它们的作用略有不同。
constraints
用于在 Gradle 项目中定义依赖约束条件。约束条件会影响到当前项目中的所有依赖项,包括 api
和 implementation
级别的依赖。例如,以下代码指定了项目中所有的 com.google.guava
的依赖都必须使用 29.0 版本:
dependencies {
constraints {
implementation("com.google.guava:guava:29.0-jre")
}
}
而 force
则用于在 Gradle 项目中为单个依赖项设置版本。与 constraints
不同,force
只会影响当前指定的依赖项。例如,以下代码指定了项目中的 com.google.guava
的依赖必须使用 29.0 版本:
dependencies {
implementation("com.google.guava:guava")
forcedModules = ["com.google.guava:guava:29.0-jre"]
}
因此,constraints
和 force
的区别在于:
constraints
会影响到当前项目中的所有依赖项,而force
只会影响单个依赖项。constraints
定义依赖的约束条件,而force
直接指定依赖的版本。
依赖替换
有一种这样的情形,假设一个第三方工具库叫 com.beecode:bap2.common:2.0
,我们自己的项目以及部分第三方库也依赖它,但是在实际使用的过程当中,发现该库有些功能不满足或者有bug,那这个时候该怎么办呢?一是提 issue 让该库的作者去修改,但是时间上来不及;二是源码拿过来本地进行修改,直接本地集成,但是要修改依赖方式,那么这个时候可以这样做:
假设我们本地 module 名称叫 bap2.common
configurations.all {
resolutionStrategy {
//远程依赖替换成本地依赖
substitute module('com.beecode:bap2.common') with project(':bap2.common')
//也可以将远程依赖换成另外的远程依赖,假设我们修改过的代码发布到自己的 maven 中央仓库后叫:com.xxx.xxx:util:3.1
substitute module('org.gradle:util:3.0') with module('com.xxx.xxx:util:3.1')
}
}
dependencySubstitution接收一系列替换规则,允许你通过substitute
函数为项目中的依赖替换为你希望的依赖项。
substitute的参数不一定是module(),针对外部依赖和内部依赖,你有两种选择:module()和project(),视具体情况自由组合。
configurations.all {
resolutionStrategy.dependencySubstitution {
substitute module("io.reactivex.rxjava2:rxjava") with module("io.reactivex.rxjava3:rxjava:3.0.0-RC1")
}
}
使用动态版本
如果你想让你的工程始终采用最新依赖,那么Gradle提供了一种方式可以始终保证采用依赖的最新版本而无需每次手工检查修改版本。使用加号+
,可以让Gradle在每次执行构建时检查远程仓库是否存在该依赖的新版本,如果存在新版本则下载选用最新版本。当然也可以指定依赖某个大版本下的最新子版本,1.+
表示始终采用该依赖最新的1.x
版本的最新依赖。
compile 'org.springframework:spring-web:5.2.+'
示例:
compile('org.hibernate:hibernate:3.1') {
// 冲突时优先使用该版本
force = true
// 依据构建名称排除
exclude module: 'cglib'
// 依据组织名称排除
exclude group: 'org.jmock'
// 依据组织名称+构件名称排除
exclude group: 'org.unwanted', module: 'iAmBuggy'
// 为本依赖关闭依赖传递特性
transitive = false
}
查看依赖信息
使用 gradle dependencies
命令可以以树形的形式显示所有依赖:
(同时,如果此前依赖的相关程序包没有下载,会先下载依赖包,再显示所有的依赖关系)
testRuntimeClasspath - Runtime classpath of source set 'test'.
+--- org.springframework.cloud:spring-cloud-starter-zipkin -> 2.1.7.RELEASE
| +--- org.springframework.cloud:spring-cloud-starter-sleuth:2.1.7.RELEASE
| | +--- org.springframework.cloud:spring-cloud-starter:2.1.5.RELEASE -> 2.1.6.RELEASE
| | | +--- org.springframework.boot:spring-boot-starter:2.1.13.RELEASE -> 2.1.6.RELEASE
| | | | +--- org.springframework.boot:spring-boot:2.1.6.RELEASE
| | | | | +--- org.springframework:spring-core:5.1.8.RELEASE
| | | | | | \--- org.springframework:spring-jcl:5.1.8.RELEASE
| | | | | \--- org.springframework:spring-context:5.1.8.RELEASE
| | | | | +--- org.springframework:spring-aop:5.1.8.RELEASE
| | | | | | +--- org.springframework:spring-beans:5.1.8.RELEASE
| | | | | | | \--- org.springframework:spring-core:5.1.8.RELEASE (*)
| | | | | | \--- org.springframework:spring-core:5.1.8.RELEASE (*)
| | | | | +--- org.springframework:spring-beans:5.1.8.RELEASE (*)
| | | | | +--- org.springframework:spring-core:5.1.8.RELEASE (*)
| | | | | \--- org.springframework:spring-expression:5.1.8.RELEASE
| | | | | \--- org.springframework:spring-core:5.1.8.RELEASE (*)
| | | | +--- org.springframework.boot:spring-boot-autoconfigure:2.1.6.RELEASE
| | | | | \--- org.springframework.boot:spring-boot:2.1.6.RELEASE (*)
| | | | +--- org.springframework.boot:spring-boot-starter-logging:2.1.6.RELEASE
| | | | | +--- ch.qos.logback:logback-classic:1.2.3
| | | | | | +--- ch.qos.logback:logback-core:1.2.3
| | | | | | \--- org.slf4j:slf4j-api:1.7.25 -> 1.7.26
| | | | | \--- org.slf4j:jul-to-slf4j:1.7.26
| | | | | \--- org.slf4j:slf4j-api:1.7.26
......
依赖的传递性
在Gradle中,依赖默认具有传递性。比如项目中依赖了spring-web
,然而spirng-web
却依赖了一堆jar包,因为Gradle的传递性依赖特性,你无需在脚本中把这些依赖都声明一遍,你只需要简单的一行,Gradle便会帮你将传递性依赖一起下载下来。
compile `org.springframework:spring-web:5.3.4.RELEASE`
传递依赖特性可以轻松地通过transitive参数进行开启或关闭:
compile("org.springframework:spring-web:4.3.4.RELEASE") {
transitive = false
}
也可以全局性的关闭依赖传递特性:
configurations.all {
transitive = false
}
缓存
Gradle 为了加快构建速度,使用了缓存机制,默认开启。
缓存策略
Gradle
依赖的版本分为正式版本
、快照版本
、动态版本
:
正式版本
:有明确指明版本号,比如implementation 'androidx.appcompat:appcompat:1.1.0'
。快照版本
:版本号后面有-SNAPSHOT
,比如implementation 'androidx.appcompat:1.1.0-SNAPSHOT'
。动态版本
:没有具体指明版本号,比如implementation 'androidx.appcompat:appcompat:1.+'
或implementation 'androidx.appcompat:appcompat:latest.release'
或implementation 'androidx.appcompat:appcompat:latest.integration'
。
缓存时效:
Gradle 的缓存策略中,对于动态版本和快照版本的缓存时间默认是 24 小时,也就是从上次更新之后,24 小时内都会使用上次的缓存。
当远程仓库更新程序包时,有时需要为缓存指定一个时效去检查远程仓库的依赖版本,Gradle
提供了cacheChangingModulesFor(int, java.util.concurrent.TimeUnit)
和 cacheDynamicVersionsFor(int, java.util.concurrent.TimeUnit)
两个方法来设置缓存的时效:
configurations.all {
resolutionStrategy {
// 每隔24小时检查远程依赖是否存在更新
cacheChangingModulesFor 24, 'hours'
// cacheChangingModulesFor 0, 'seconds' // 每次构建都检查远程依赖是否存在更新
// cacheChangingModulesFor 60, 'minutes' // 每隔60分钟检查远程依赖是否存在更新
// 动态版本缓存设置: 每隔10分钟检查是否存在更新
cacheDynamicVersionsFor 10 * 60, 'seconds'
}
}
缓存文件的存放位置:
${GRADLE_USER_HOME}/caches/
规则:
如果在本地maven仓库中找不到,那么在其他远程仓库下载的jar包不会存放到本地maven仓库中,而是放到自己的缓存目录下。
清除缓存
使用 gradle build 构建的时候加上 --refresh-dependencies
选项就会删除缓存,重新下载相关jar包。
开关缓存
--build-cache, --no-build-cache
插件
gradle 插件库地址:https://plugins.gradle.org
引用插件的语法:(两种声明方式)
plugins {
id 'java'
id 'eclipse'
}
apply plugin: 'maven-publish'
springboot
springboot gradle plugin 官方文档
利用springboot 插件,在打包时写入构建信息
apply plugin: 'org.springframework.boot'
//
springBoot {
buildInfo {
properties {
additional = [
'Implementation-Title': project.name,
'Implementation-Version': project.version,
'Built-By': System.getProperty('user.name'),
'Built-Time': new Date().format("yyyy-MM-dd HH:mm:ss"),
'Git-Branch': getGitBranch(),
'Git-Commit-Id': getGitCommit(),
'Git-Commit-Time': getGitCommitTime()
]
}
}
}
// 获取当前分支名称
static def getGitBranch() {
try {
def branch = 'git rev-parse --abbrev-ref HEAD'.execute().text.trim()
return branch ?: 'unknown'
} catch (Exception e) {
System.err.println("fail to get branch, errMsg:" + e.getMessage())
return 'unknown'
}
}
// 获取当前提交的记录的commitId
static def getGitCommit() {
try {
def commit = 'git rev-parse HEAD'.execute().text.trim()
return commit ?: 'unknown'
} catch (Exception e) {
System.err.println("fail to get commit id, errMsg:" + e.getMessage())
return 'unknown'
}
}
// 获取当前Git提交的时间
static def getGitCommitTime() {
try {
def commitTime = 'git show -s --format=%ct HEAD'.execute().text.trim()
return commitTime ? new Date(Long.parseLong(commitTime) * 1000L).format("yyyy-MM-dd HH:mm:ss") : 'unknown'
} catch (Exception e) {
System.err.println("fail to get commit time, errMsg:" + e.getMessage())
return 'unknown'
}
}
编写web接口:(记得放开接口权限)
@RestController
@RequestMapping("/query/app")
public class AppBuildInfoController {
public static final String BUILD_TIME = "Built-Time";
public static final String GIT_BRANCH = "Git-Branch";
public static final String GIT_COMMIT_ID = "Git-Commit-Id";
public static final String GIT_COMMIT_TIME = "Git-Commit-Time";
@Autowired
private BuildProperties buildProperties;
@GetMapping( "/buildInfo")
public AppBuildInfo buildInfo() {
String builtTime = buildProperties.get(BUILD_TIME);
String gitBranch = buildProperties.get(GIT_BRANCH);
String gitCommitId = buildProperties.get(GIT_COMMIT_ID);
String gitCommitTime = buildProperties.get(GIT_COMMIT_TIME);
AppBuildInfo buildInfo = new AppBuildInfo(gitBranch, gitCommitId, gitCommitTime, builtTime);
return buildInfo;
}
}
java
在工程根目录新增 build.gradle 文件,添加一行代码:
apply plugin: 'java'
此时Java 插件里的任务被引入,使用 gradle tasks 命令再次查看可用任务列表,多了3个任务分组:
它们分别是 构建任务、生成JavaDoc 任务、执行单元测试和校验任务。
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.
Documentation tasks
-------------------
javadoc - Generates Javadoc API documentation for the main source code.
Verification tasks
------------------
check - Runs all checks.
test - Runs the unit tests.
Gradle 默认会从 src/main/java
搜寻打包源码,在 src/test/java
下搜寻测试源码。并且 src/main/resources
下的所有文件按都会被打包,所有 src/test/resources
下的文件 都会被添加到类路径用以执行测试。所有文件都输出到 build 下,打包的文件输出到 build/libs 下。
clean
删除 build 构建目录
assemble
编译并打包项目(不会执行单元测试)。
一些其他插件可能会增强这个任务的功能。例如,如果采用了 War 插件,这个任务便会为你的项目打出 War 包。
build
编译并打包项目,执行单元测试
check
编译并测试代码。一些其他插件也可能会增强这个任务的功能。例如,如果采用了 Code-quality 插件,这个任务会额外执行 Checkstyle
构建项目
此时执行 gradle build 命令进行项目构建,执行成功后,会在根目录自动新增 build 文件夹,里面有3个文件夹:
build
├── classes
│ └── main
│ └── hello
│ ├── Greeter.class
│ └── HelloWorld.class
├── libs
│ └── gs-gradle-0.1.0.jar
└── tmp
└── jar
└── MANIFEST.MF
编译警告设置
Gradle 脚本用于设置 Java 编译器的一系列警告选项。这些选项会影响编译器在编译 Java 代码时生成警告的方式。
具体来说,该脚本通过 compileJava.options*.compilerArgs 配置了一系列警告选项。下面是每个选项的含义:
-Xlint:serial: 当序列化类缺少 serialVersionUID 时生成警告。
-Xlint:varargs: 当使用非安全的变长参数方法时生成警告。
-Xlint:cast: 当强制类型转换时生成警告。
-Xlint:classfile: 当类文件版本与源版本不匹配时生成警告。
-Xlint:dep-ann: 当使用不赞成的注释或注释类型时生成警告。
-Xlint:divzero: 当除以零发生时生成警告。
-Xlint:empty: 当空语句块(例如空的 if 或 while 语句)发生时生成警告。
-Xlint:finally: 当 finally 块不能完成时生成警告。
-Xlint:overrides: 当方法覆盖时没有正确覆盖父类的方法时生成警告。
-Xlint:path: 当生成的路径长度超过限制时生成警告。
-Xlint:processing: 当在注解处理期间发生错误时生成警告。
-Xlint:static: 当使用静态成员访问非静态成员时生成警告。
-Xlint:try: 当在 try 块中没有 catch 或 finally 时生成警告。
-Xlint:fallthrough: 当 switch 语句中缺少 break 或 return 时生成警告。
-Xlint:rawtypes: 当使用未参数化的泛型类型时生成警告。
-Xlint:deprecation: 当使用已过时的 API 时生成警告。
-Xlint:unchecked: 当未经检查的转换发生时生成警告。
-Xlint:-options: 关闭所有由 -Xlint 开启的选项。
-Werror: 将警告视为错误,导致编译失败。
通过配置这些选项,您可以在编译 Java 代码时更严格地检查代码中的问题,并确保代码质量和可维护性。
apply plugin: 'java'
compileJava.options*.compilerArgs = [
"-Xlint:serial", "-Xlint:varargs", "-Xlint:cast", "-Xlint:classfile",
"-Xlint:dep-ann", "-Xlint:divzero", "-Xlint:empty", "-Xlint:finally",
"-Xlint:overrides", "-Xlint:path", "-Xlint:processing", "-Xlint:static",
"-Xlint:try", "-Xlint:fallthrough", "-Xlint:rawtypes", "-Xlint:deprecation",
"-Xlint:unchecked", "-Xlint:-options", "-Werror"
]
eclipse
引入插件:
apply plugin: "eclipse"
eclipse 插件自带2个任务:cleanEclipse
和 eclipse
IDE tasks
---------
cleanEclipse - Cleans all Eclipse files.
eclipse - Generates all Eclipse files.
执行 gradle eclipse
命令,会在当前目录下生成 eclipse 所需要的文件:
.settings
.classpath
.project
war
引入插件:
apply plugin: 'war'
maven-publish
默认情况下,Gradle 只能读取Maven仓库的构件,并不能发布本地构件到Maven,如果想发布到Maven仓库,需要使用 maven-publish 插件。
该插件提供的功能如下:
Publishing tasks
----------------
generatePomFileForMavenJavaPublication - Generates the Maven POM file for publication 'mavenJava'.
publish - Publishes all publications produced by this project.
publishMavenJavaPublicationToMavenLocal - Publishes Maven publication 'mavenJava' to the local Maven repository.
publishMavenJavaPublicationToMavenRepository - Publishes Maven publication 'mavenJava' to Maven repository 'maven'.
publishToMavenLocal - Publishes all Maven publications produced by this project to the local Maven cache.
配置:
apply plugin: 'maven-publish'
publishing { // 配置你的发布
publications { // 配置发布的产出包,一个项目可以有多个产出
mavenJava(MavenPublication) {
from components.java
artifact sourcesJar //可选功能:生成源码档案
artifact javadocJar //可选功能:生成Javadoc
}
}
repositories { // 配置发布的仓库,有多个可选择
mavenLocal() // 本地仓库默认位于 $USER_HOME/.m2/repository
maven {
credentials {
username publishUsername
password publishPassword
}
if (version.endsWith('-SNAPSHOT')) {
url publishSnapshotRepo
} else {
url publishReleaseRepo
}
}
}
}
task sourcesJar(type: Jar, dependsOn: classes) {
classifier = 'sources'
from sourceSets.main.allSource
}
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
}
将一个Maven 项目转化为Gradle项目:(使用命令一键转换)
gradle init --type pom
自定义插件
apply plugin: 'com.beecode.metadata-module'
任务 task
查看任务
//查看任务列表
gradle tasks
//默认情况下,此报表仅显示已分配给任务组的任务。可以使用 --all 选项查看任务。
gradle tasks --all
//查看某个任务的属性:位置、类型、描述
gradle -q help --task libs
Detailed task information for libs
Paths
:api:libs
:webapp:libs
Type
Task (org.gradle.api.Task)
Description
Builds the JAR
Group
build
一个Task包含若干Action。所以,Task有 doFirst和 doLast 两个钩子函数,用于添加需要最先执行的Action和需要和需要最后执行的Action。Action就是一个闭包。闭包,英文叫Closure,是Groovy中非常重要的一个概念。
任务依赖
build.gradle
task compile << {
println 'compiling source'
}
task compileTest(dependsOn: compile) << {
println 'compiling unit tests'
}
task test(dependsOn: [compile, compileTest]) << {
println 'running unit tests'
}
task dist(dependsOn: [compile, test]) << {
println 'building the distribution'
}
由于每个任务仅会被调用一次,所以调用 gradle dist test 与调用 gradle test 效果是相同的。
注意,task的doLast
和 <<
具有相同的语义,都是任务的一个动作。
task hello << {
println 'Hello world!'
}
//等价于
task hello {
doLast {
println 'Hello world!'
}
}
排除任务
你可以用命令行选项 -x
来排除某些任务
gradle dist -x test
任务类型
默认的任务继承自 org.gradle.api.DefaultTask
常见任务类型 | 该类型任务的作用 |
---|---|
Delete | 删除文件或目录 |
Copy | 将文件复制到目标目录中。此任务还可以在复制时重命名和筛选文件。 |
CreateStartScripts | 创建启动脚本 |
Exec | 执行命令行进程 |
GenerateMavenPom | 生成 Maven 模块描述符(POM)文件。 |
GradleBuild | 执行 Gradle 构建 |
Jar | 组装 JAR 归档文件 |
JavaCompile | 编译 Java 源文件 |
Javadoc | 为 Java 类 生 成 HTML API 文 档 |
PublishToMavenRepository | 将 MavenPublication 发布到 mavenartifactrepostal。 |
Tar | 组装 TAR 存档文件 |
Test | 执行 JUnit (3.8.x、4.x 或 5.x)或 TestNG 测试。 |
Upload | 将 Configuration 的构件上传到一组存储库。 |
War | 组装 WAR 档案。 |
Zip | 组装 ZIP 归档文件。默认是压缩 ZIP 的内容。 |
如果想看更详细的gradle 自带Task 类型,请参考官方文档
示例:
//复制任务
task buildCopy(type: Copy) {
from 'build/classes/mk/main'
into 'src/main/resources'
include '**/*.jmx'
}
//压缩任务
task build(type: Zip) {
subprojects.forEach {
dependsOn it.getTasksByName("build", false), it.getTasksByName("buildCopy", false)
from it.tasks.jar.archivePath
}
destinationDir = new File(buildDir, "archive")
}
//删除任务
tasks.register('removeInput', Delete) {
delete 'inputs/3.txt'
}
自定义任务
在 Gradle 构建脚本中,tasks.register
和 task
都是用于定义任务的方法,但它们之间有一些重要的区别:
tasks.register
方法是动态创建任务的一种方式。它允许在构建脚本执行期间动态地创建任务,这意味着你可以根据需要在任何地方创建任务,比如在条件语句中、循环中或者基于外部配置参数。- 通过
tasks.register
方法创建的任务可以使用 Groovy 闭包来定义任务的行为,这样可以更灵活地定制任务的行为。闭包中的代码会在任务执行时动态地执行。 - 由于
tasks.register
方法是动态的,所以可以在 Gradle 的配置阶段和执行阶段的任何时候调用,而不受限于顺序或位置。
task
方法是静态创建任务的一种方式。它允许在构建脚本的顶层直接定义任务,任务会在 Gradle 配置阶段被创建。- 通过
task
方法创建的任务不能使用 Groovy 闭包来定义任务的行为,只能在顶层定义任务的配置,比如依赖关系、任务行为等。 - 由于
task
方法是静态的,所以必须在 Gradle 配置阶段的顶层直接调用,不能在条件语句或循环中调用。
因此,tasks.register
和 task
方法都用于定义任务,但是 tasks.register
方法更灵活,可以在运行时动态创建任务,而 task
方法则更适合静态地定义任务。
build.gradle 文件:
task buildCopy(type: Copy) {
from 'build/classes/mk/main'
into 'src/main/resources'
include '**/*.jmx'
}
tasks.register("casPushDockerImage", DockerPushImage) {
dependsOn("casBuildDockerImage")
def imageTag = "${project.'cas.version'}"
images.add("apereo/cas:${imageTag}${imageTagPostFix}")
images.add("apereo/cas:latest${imageTagPostFix}")
if (dockerUsername != null && dockerPassword != null) {
username = dockerUsername
password = dockerPassword
}
doLast {
def out = services.get(StyledTextOutputFactory).create("cas")
out.withStyle(Style.Success).println("Pushed CAS images successfully.")
}
}
这段 Gradle 脚本定义了一个名为 casPushDockerImage
的自定义任务,并使用 DockerPushImage
任务作为任务的类型。该任务的作用是将构建好的 Docker 镜像推送到 Docker 仓库中。下面是对该脚本的解释:
tasks.register("casPushDockerImage", DockerPushImage) { ... }
:使用tasks.register()
方法注册一个名为casPushDockerImage
的自定义任务,并指定任务类型为DockerPushImage
。接着使用闭包{ ... }
包裹任务的配置代码。dependsOn("casBuildDockerImage")
:通过dependsOn()
方法,指定任务casPushDockerImage
依赖于另一个名为casBuildDockerImage
的任务。这意味着在执行casPushDockerImage
任务之前,必须先执行casBuildDockerImage
任务。def imageTag = "${project.'cas.version'}"
:定义了一个变量imageTag
,用于存储项目中cas.version
属性的值。${project.'cas.version'}
表示获取项目属性cas.version
的值。
默认任务
Gradle 允许在脚本中定义一个或多个默认任务。使用 defaultTasks 指令配置默认任务。
defaultTasks 'clean', 'run'
task clean {
println 'Default Cleaning!'
}
task run {
println 'Default Running!'
}
gradle -q 命令的输出
> gradle -q
Default Cleaning!
Default Running!
构建脚本
定义属性
定义属性有3种方式:
- 在构建脚本中使用
ext
指令声明; - 在
gradle.properties
文件中声明; - 使用
-D
命令选项定义系统属性;
外部属性
ext {
aminoVersion = "2.1.+"
inzVersion = "1.0.+"
springVersion = "5.0.6.RELEASE"
springBootVersion = "2.0.2.RELEASE"
springSecurityVersion = "5.0.3.RELEASE"
springSessionVersion = "2.0.2.RELEASE"
hibernateVersion = "5.3.0.Final"
lib = [
np_authz: "com.jiuqi:np.authz:${npAuthzVersion}",
spring_aop: "org.springframework:spring-aop:${springVersion}",
spring_beans: "org.springframework:spring-beans:${springVersion}",
]
}
dependencies {
compile lib.np_authz
}
多项目构建
在根项目上执行名为“myTask”的任务:
$ gradle myTask
$ gradle :myTask
在多项目构建中,可以使用 :
分隔子项目名称和任务名称来执行子项目任务。从根项目运行时,以下内容是等效的:
$ gradle :my-subproject:taskName
$ gradle my-subproject:taskName
您还可以使用仅包含任务名称的任务选择器为所有子项目运行任务。例如,当从根项目目录调用时,这将为所有子项目运行“测试”任务:
$ gradle test
从子项目中调用 Gradle 时,应省略项目名称:
$ cd my-subproject
$ gradle taskName
执行多个任务:
$ gradle clean build
查看项目属性:
# 查看根项目属性
gradle properties
# 查看指定项目属性
gradle project1:properties
使用 settings.gradle 文件构建多项目
rootProject.name = "inz-metadata"
include "inz.card.metadata"
include "inz.assets.business.metadata"
include "inz.assets.metadata"
include "inz.contract.metadata"
include "inz.crm.metadata"
include "inz.news.metadata"
include "inz.portal.metadata"
include "inz.property.metadata"
include "inz.statistics.metadata"
include "inz.workflow.metadata"
include "inz.psi.metadata"
注:提供的项目路径是相对于根目录,记住冒号:
用来分隔目录层次;
使用 gradle projects
指令查看所有的子项目:
>gradle projects
Root project 'inz-metadata'
+--- Project ':inz.assets.business.metadata'
+--- Project ':inz.assets.metadata'
+--- Project ':inz.card.metadata'
+--- Project ':inz.contract.metadata'
+--- Project ':inz.crm.metadata'
+--- Project ':inz.news.metadata'
+--- Project ':inz.portal.metadata'
+--- Project ':inz.property.metadata'
+--- Project ':inz.psi.metadata'
+--- Project ':inz.statistics.metadata'
\--- Project ':inz.workflow.metadata'
配置子项目
// 配置子项目
configure(subprojects) { project ->
apply from: "../common.gradle"
repositories {
mavenCentral()
maven {
url "http://nvwa.jiuqi.com.cn/nexus/repository/maven-nr-public/"
credentials {
username nexusUsername
password nexusPassword
}
}
}
dependencies {
compile enforcedPlatform("com.jiuqi.nvwa.dependency:nr-dev-dependencies:1.17.28")
}
}
配置对象
在 Gradle 构建脚本中,configure
方法用于对 Gradle 对象进行配置。它允许你在构建脚本中对特定的对象进行定制,比如项目对象、任务对象等。configure
方法接受一个闭包作为参数,在闭包中可以对对象进行配置。
以下是 configure
方法的基本用法:
configure(object) {
// 在这里配置对象的属性和行为
}
其中,object
可以是项目对象、任务对象或者其他 Gradle 对象。
示例:
// 配置项目对象
configure(project) {
version = '1.0'
group = 'com.example'
}
// 配置自定义任务对象
task customTask {
doLast {
println "This is a custom task"
}
}
configure(customTask) {
description = 'This is a custom task'
group = 'Custom tasks'
}
在上面的示例中,我们对项目对象和自定义任务对象进行了配置。对于项目对象,我们设置了版本号和组名;对于自定义任务对象,我们设置了任务的描述和分组。通过 configure
方法,可以将多个配置操作组织在一起,并使得构建脚本更加清晰和易于维护。
日志
日志级别
Gradle 定义了6个日志级别
日志级别 | 描述 |
---|---|
ERROR | 错误消息 |
QUIET | 重要的信息消息 |
WARNING | 警告消息 |
LIFECYCLE | 进度信息消息 |
INFO | 信息性消息 |
DEBUG | 调试消息 |
日志级别的命令行选项
选项 | 输出日志级别 |
---|---|
没有日志选项 | LIFECYCLE 及更高 |
--quiet |
QUIET 及更高 |
--info |
INFO 及更高 |
--debug |
DEBUG 及更高 |
还可以在 gradle.properties 文件中配置gradle 的日志输出级别
org.gradle.logging.level=(quiet,warn,lifecycle,info,debug)
使用 -s 或 --stacktrace 选项运行以获取堆栈跟踪。
使用 --info 或 --debug 选项运行以获得更多日志输出。
使用 --scan 运行以获得完整的见解。
编写日志消息
使用标准输出写日志
println 'A message which is logged at QUIET level'
Gradle 还提供了一个 logger 属性给构建脚本,它是一个 Logger 实例。该接口扩展自 SLF4J的 Logger 接口,并添加了几个 Gradle 的特有方法。下面是关于如何在构建脚本中使用它的示例:
logger.quiet('An info log message which is always logged.')
logger.error("Page not found, error code: {}", from)
logger.warn('A warning log message.')
logger.lifecycle('A lifecycle info log message.')
logger.info('An info log message.')
logger.debug('A debug log message.')
Gradle Wrapper
Gradle Wrapper 是一个脚本,它调用已声明的 Gradle 版本(如果不存在会自动下载)。 目的是使开发人员可以快速启动并运行 Gradle 项目,而无需手动安装和配置。
在build.gradle 中配置wrapper的gradleVersion:
wrapper{
gradleVersion = '6.8.3'
}
使用 gradlew
命令前需要把 wrapper 相关的文件初始化,以获得 wrapper 脚本:
gradle wrapper
此命令执行后会自动生成四个文件:
.gradle
gradle
gradlew
gradlew.bat
注:gradle init 命令也会将四个文件初始化出来,相当于默认可以使用 gradlew 命令。
目录结构:
.
├── a-subproject
│ └── build.gradle
├── settings.gradle
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
└── gradlew.bat
查看 gradlew 当前使用的版本:
gradlew -v
在 ./gradle/wrapper/gradle-wrapper.properties
配置文件中修改版本,就可以随意更换gradle 版本进行构建,而不需要全局更改配置。
或使用命令修改gradle 版本:
gradlew wrapper --gradle-version=7.5.1
守护进程
Gradle 守护进程是一个后台进程, 它运行着繁重的构建, 然后在构建等待下一次构建的之间保持自身存在. 这使得数据和代码在下一次构建前已经准备好,并存入内存中. 这显著的提高了后续构建的性能. 启用Gradle守护进程是一种节约构建时间的廉价方式。
强烈建议在所有开发机器上启用Gradle的守护进程.但是不推荐在持续集成和构建服务器环境下启用守护进程。
Gradle自动管理守护进程.如果构建环境配置为利用后台程序,如果在没有可用守护进程,就会自动启动一个守护进程,或者使用现有的空闲的兼容守护进程.如果一个守护进程在3个小时内没有使用,它将会自我终结.一旦配置开发环境为使用的守护进程,守护进程通常是隐形的,容易被遗忘的。
--daemon, --no-daemon
实践
使用gradle 命令快速创建一个Java项目
gradle init --type java-application
设置MANIFEST.MF
在build.gradle 文件中 添加如下配置
// 配置编译选项
compileJava.options.encoding = 'UTF-8'
compileTestJava.options.encoding = 'UTF-8'
// 配置打包选项
jar {
manifest {
attributes(
'Main-Class': 'com.example.Main'
)
}
}
Groovy 语法
/**
* groovy 语法: 非常随意
* 末尾分号可以省略, 括号可以省略; 弱类型语言,def 定义变量
*
*/
def i = "Jackpot"
print i
//groovy 闭包
//定义一个闭包
def b1 = {
print "hello b1"
}
new Date().format("yyyy-MM-dd HH:mm:ss")
static def getGitBranch() {
try {
def branch = 'git rev-parse --abbrev-ref HEAD'.execute().text.trim()
return branch ?: 'unknown'
} catch (Exception e) {
System.err.println("fail to get branch, errMsg:" + e.getMessage())
return 'unknown'
}
}
README
作者:银法王
修订:
2021-04-27 第一次
2022-06-29 完善
2024-04-03 完善
参考: