Gradle
最后更新于
这有帮助吗?
最后更新于
这有帮助吗?
官方文档:https://docs.gradle.org/current/userguide/userguide.html
构建性能
最高
最低
居中
仓库
开发者自己处理
maven仓库
支持各种仓库
依赖管理
ivy管理
GAV管理
GNV管理
插件支持
实现方便
实现较难
实现方便
遵循特定的目录结构
No
Yes
Yes
配置文件
xml文件(繁琐)
xml文件
代码脚本,便于写业务逻辑
侧重点
小型项目构建
项目包管理
大型项目构建
目前地位
使用较少
目前主流
未来趋势
gradle init
创建gradle项目
gradle init --type pom
将maven项目转换为gradle
gradle classes
编译源代码与配置文件
gradle test
编译测试代码,生成测试报告
gradle build
构建项目
gradle build -x test
构建项目,且跳过测试
gradle clean
清空build目录
~/.gradle/init.gradle
是gradle的全局配置脚本,他有四种方式可以配置,优先级从高到低:
运行指令时指定初始化脚本:gradle -init-script yourdir/init.gradle -q taskName
,也可以指定多个init文件
$USER_HOME/.gradle/init.gradle
文件
$USER_HOME/.gradle/init.d/*.gradle
多个文件
$GRADLE_HOME/init.d/*.gradle
多个文件
gradle会按照上述1-4的顺序依次执行这些文件,如果文件夹中包含多个脚本文件,则会按照字母顺序依次执行。
配置远程仓库地址:
Gradle下载的依赖的位置位于$USER_HOME/.gradle/caches
,如果配置了$GRADLE_USER_HOME
环境变量,将会放在该目录下的caches
子目录下。
注意,不要将caches目录与MVN的本地仓库指向统一位置,因为caches下载文件与mvn仓库的存放方式不同。
Gradle Wrapper是对Gradle的一层包装,用于解决实际开发中不同项目需要不同版本的Gradle问题:
项目拉取者本地没有Gradle
项目拉去这本地Gradle版本与项目不一致
这个时候就需要gradle了。
Gradle Wrapper 提供了如下文件:
--gradle-version
用于指定使用Gradle版本
--gradle-distribution-url
用于指定下载gradle发行版本的url(原来的可能很慢)
修改properties 文件即可:
执行 ./gradlew build
读取 ./gradle/gradle-wrapper.properties
配置文件
将配置文件中的指定版本的gradle下载到 $GRADLE_HOME/wrapper/dists
目录下(如果已经有了将不会再下载了)
并构建本地缓存($GRADLE_HOME/caches
)
之后执行的所有的 .gradlew
命令实际都是调用的目标版本的gradle命令
Gradle项目的生命周期分为三大阶段:
Initialization 初始化
执行初始化脚本(init.d/*.gradle
)
执行settings.gradle
,主要包含当前项目声明以及当前项目子模块声明
生成项目工程树
Configuration 配置
根据初始化阶段得到的项目工程树
依次调用每个模块的build.gradle
脚本
调用顺序为先加载跟工程的,再加载所有的二级子工程的脚本,然后是三级子工程所有...
加载的build.gradle
脚本最终会生成一个由task组成的有向无环数
Execution 执行
根据有向无环数依次执行task,完成构建
主要是在项目初始化阶段为项目工程树做准备:
位于项目根路径
名称必须为 settings.gradle
定义了当前gradle项目以及子项目的名称
每个项目只能有一个settings.gradle
文件,他在gradle内部会生成一个org.gradle.api.initialization.Settins
实例
是gradle的识别标志,没有该文件不会认为该项目是一个gradle项目
使用inclue('路径')
引入项目模块
在gradle中,
:
可以试做/
,如果以:
开头,代表是根目录开始。
build.gradle
是一个gradle构建脚本,支持java、groovy语法
每个project实例对应一个build.gradle
脚本,文件中的所有方法调用都是调用的project对象的实例方法。
RootProject也可以拥有一个build.gradle
脚本文件,通常用来设置子project的一些公共信息,比如仓库、所有应用依赖的插件、所有应用的依赖项
下面是一个标准的 build.gradle
:
自带属性:group,name,version 对应maven的GAV,用于表示项目的坐标。其中,group与version信息配置在build.gradle
文件中,而name则是配置在settings.gradle
文件中。
build.gradle:
settings.gradle:
可以使用ext方法定义自定义属性,并引用:
ext信息不仅可以放在build.gradle中,还可以放在任务中:
定义仓库,gradle在下载依赖的时候,会从上到下依次从每个仓库中寻找需要的依赖。如果找到将会停止向下搜索,如果找不到则继续向下查找。
在gradle中,依赖有三种方式:
本地依赖,依赖本地的某个jar,可以通过文件集合、文件树的方式指定
项目依赖,依赖某个定义在settings.gradle
的project
直接依赖,依赖类型 依赖组名 依赖名称 依赖版本号
当执行build命令时,gradle就会去配置的依赖仓库中下载对应的jar,并应用到项目中。
相当于maven的scope:
compileOnly
由java插件提供,适用于编译器需要,但是打包不需要的情况
servlet-api容器已经提供
runtimeOnly
由java插件提供,只在运行期有效,编译器不需要
mysql的驱动包,编译期间不需要知道驱动包的细节,但是运行时必须有
implementation
由java插件提供,针对源码目录,在编译运行都有效
比如commons-lang、spring等
testCompileOnly
由java插件提供,用于编译测试的依赖项
testRuntimeOnly
由java插件提供,用于运行时需要的依赖项,编译不需要
testImplementation
由java插件提供,测试编译、运行期间都需要
api
由java-library插件提供,与implementation基本一致,但是提供了依赖传递的效果
compileOnlyApi
由java-library插件提供,在编译器有效,运行期无效,其他与api一致
api
与implementation
的区别,假设有四个模块:
A implementation B, B implementation C, A模块编译期间无法使用C中的类
A implementation B, B api C,则A可以在编译期间使用C种的类
A implementation B, B implementation C, C api D,则B编译期间可以使用A种的类,但是A不能使用B中的类
A implementation B, B api C, C api D, 这样可以使用D
总的来说,api标记了这个依赖项是否可以被需要依赖当前项目的人使用;而implementation则代表当前依赖项仅供当前项目使用,不能被其他需要依赖该项目的项目使用。因为api的模块需要暴露给别的模块使用,将会影响编译速度。在开发过程中,优先选择implementation
,如果涉及到多模块的依赖,再考虑使用api。注意当项目中拥有大量的api依赖项会显著增加构建时间。
高版本gradle已经废弃了 api,使用implementation即可
在编译期间,如果系统中出现同一依赖的不同版本,构建系统应该选择什么版本进行构建的问题:
项目依赖A模块,A模块依赖了log4j1.0
项目还依赖了B模块,B模块依赖了log4j2.0
编译期间不知道该使用log4j1.0还是log4j2.0
默认情况下,Gradle会使用最新的jar,比如上述案例就会使用log4j2.0的jar,自动剔除1.0的jar。
如果不想遵循默认的规则,可以通过exclude
手动排除某个冲突的jar:
或者禁用引用包的依赖传递,这样打包时也可以提出某个依赖(不建议使用):
或者强制使用某个版本,让项目目中所有涉及当前依赖的模块都是用这个版本:
不建议使用。
主要解决问题:如果在某个build.gradle
中定义一些配置以及依赖,那么这些配置依赖只会对当前项目有效,他的子项目不会生效。
allprojects 设置当前工程以及当前工程的所有子工程一起设置,通常放在rootproject/build.gradle
中:
而subprojects是对当前工程下的所有子工程设置,当前工程下不设置:
subprojects和allprojects可以为项目设置公用的插件、依赖、属性,此外,还可以使用project方法,对某个子工程进行一些独立的设置:
注意:
subproject1 名字定义在了settings.gralde
中
在allprojects、subprojects、project不支持语法 plugins {}
应用插件,需要使用apply plugin: 'xx'
替换
设置项目源集,比如java的默认源码目录src/main/java
,以及构建结果目录。
前两者是旧的插件依赖方式,plugins则是新的插件依赖方式。
buildscript里是gradle脚本执行所需依赖,分别是对应的maven库和插件:
buildScript必须在build.gradle
文件的最顶端,因为需要为执行脚本做准备
对于多项目构建,项目的 buildScript 方法声明的依赖关系可用于其所有子项目的构建脚本,类似allprojects、subprojects
这里定义的依赖可能是普通依赖,也可能是插件依赖
Project实质上是Task对象的集合。一个Task表示一个逻辑较为独立的执行过程,比如编译、文件拷贝、打包等,甚至是一个简单的系统命令。一个Task可以读取和设置Project的Property以完成特定的操作。
在 build.gradle
中定义一个简单的Task:
执行task:
task中的所有行为是一个action实例,这些实例会放入到一个列表中,列表的最前面是一个或者多个doFirstAction
,最后面则是一个或者多个doLastAction
。先添加的将会放在列表的前面。
type
指定父task,基于另一个task创建新的task
DefaultTask
overwrite
是否替换存在的Task,这个和type配合使用
false
dependsOn
配置任务的依赖关系
[]
action
添加到任务中的Action或者一个闭包
null
description
任务描述
null
group
任务分组,比如test
、build
等
null
示例:
默认的task继承自DefaultTask类型,如果要完成某些具体的操作,完全需要我们自己去编写gradle脚本,这样肯定有些麻烦,所以提供了type属性去继承某个task,复用他的一些逻辑。官方为我们提供了一些默认的TaskType使用:
Delete
删除文件或目录
Copy
将文件复制到目标目录中,还可以在复制时重命名和筛选文件
CreateStartScripts
创建启动脚本
Exec
执行命令进程
GenerateMavenPom
生成Maven Pom文件
GradleBuild
执行Gradle构建
Jar
组装Jar归档文件
JavaCompiler
编译Java源码
Javadoc
为Java代码生成HTML API
PublishToMavenRepository
推送到远程maven仓库
Tar
组装tar归档文件
Test
执行Junint或者TestNG测试
Upload
将Configuration的构建上传到一组存储库
War
组装war归档文件
Zip
组装Zip归档文件
示例(删除构建目录):
或者使用类继承的方式:
build.gradle
可以定义多个task,多个task可能存存在依赖关系:
有三种方式控制任务的执行顺序:
dependsOn 强依赖方式(不推荐)
通过 Task 输入输出(不推荐)
通过API指定执行顺序
可以为任务设置超时时间,如果大于超时时间,则会抛出一个异常,并且中断后面的任务执行:
只有满足目标条件的时候,任务才会执行,否则将会跳过。
输出结果:
拷贝文件,常产用于生成构建内容。下面是通过CopyTask的方式:
project也提供了相应的copy方法:
文件归档:
默认情况下,如果要执行某个任务,需要通过gradle -q taskName
命令指定任务名称,然后才可以执行任务。如果想通过gradle
直接执行某些任务,需要将任务设置为默认的任务:
运行gradle命令,将会显示:
在项目中引用插件,可以:
添加插件定义好的task到项目中,帮助我们完成编译、测试、打包
添加一些新的依赖类型到项目中
向项目中扩展一些新的属性以及方法,比如加入插件之后,可以设置jdk的版本信息
插件可以对项目进行一些约定俗称的配置
Gradle插件分类:
脚本插件
二进制插件(对象插件)
内部插件
第三方插件
自定义插件
脚本插件是在项目中定义.gradle
结尾的gradle脚本文件,然后引入到build.gradle
中,比如下面定义了一个version.gradle
的脚本,记录了当前java的版本信息:
在build.gradle
引如这个脚本,并创建一个Task使用脚本中生命的变量:
所谓对象插件就是实现 org.gradle.api.Plugin
接口的插件,每一个插件都有且必须有一个 plugin id。可以通过apply使用插件:
内部也是核心插件,可以在 https://docs.gradle.org/current/userguide/plugin_reference.html 查看所有的核心插件。
使用核心插件:
或者使用apply:
不是gradle自带的,而是由其他第三方提供的插件,一般需要配置对应的仓库和类路径,否则找不到插件:
如果插件已经被托管到 https://plugins.gradle.org 中,可以使用如下方式直接引入插件:
通过实现Plugin<Project>
接口创建一个project的插件,一个插件中可能包含多个task:
上述方式只支持在一个模块中使用插件,如果想要多个模块之间共享插件,可以使用buildSrc的方式:
buildSrc
是Gradle的默认插件目录,编译插件时会自动识别这个目录,将其编译为插件。
先在根项目目录建立一个名称为buildSrc
的gradle模块,并且不在settings.gradle
中include这个模块,只保留build.gradle
以及src/main
。
修改build.gradle
如果多个项目之间需要使用同一个插件,我们将上述做好的插件单独抽成一个插件项目并将依赖包上传到maven私服中即可。如果要使用仓库,项目只需要依赖这个插件依赖,并apply即可:
使用 maven-publish 插件提供的task发布即可。
发布插件的官方文档:https://docs.gradle.org/current/userguide/publishing_gradle_plugins.html
如何引入插件
插件所包含的主要task
插件约定的工程结构(约定优于配置)
插件提供的依赖管理以及依赖的类型、
插件提供的额外的属性,可以再build.gradle中使用
Java插件示例,参考官方文档: https://docs.gradle.org/current/userguide/java_plugin.html#java_plugin