Gradle 是一款Google 推出的基于 JVM、通用灵活的项目构建工具,支持 Maven,JCenter 多种第三方仓库;支持传递性依赖管理、废弃了繁杂的xml 文件,转而使用简洁的、支持多种语言(例如:java、groovy 等)的 build 脚本文件。
官网地址:
学习Gradle 的原因:
- 目前已经有相当一部分公司在逐渐使用Gradle作为项目构建工具了。
- 作为Java开发程序员,如果想下载Spring、SpringBoot等Spring家族的源码,基本上基于Gradle构建的。
总之,虽然目前市面上常见的项目构建工具有Ant、Maven、Gradle,主流还是Maven,但是未来趋势Gradle。
Ant
: 2000 年 Apache 推出的纯Java 编写构建工具,通过 xml[build.xml]文件管理项目优点:使用灵活,速度快(快于 gradle 和 maven),
缺点:Ant 没有强加任何编码约定的项目目录结构,开发人员需编写繁杂XML 文件构建指令,对开发人员是一个挑战。
Maven
: 2004 年Apache 组织推出的再次使用xml 文件[pom.xml]管理项目的构建工具。
优点: 遵循一套约定大于配置的项目目录结构,使用统一的GAV 坐标进行依赖管理,侧重于包管理。缺点:项目构建过程僵化,配置文件编写不够灵活、不方便自定义组件,构建速度慢于 gradle。
Gradle:
2012 年Google 推出的基于Groovy 语言的全新项目构建工具,集合了Ant 和 Maven 各自的优势。
优点:集 Ant 脚本的灵活性+Maven 约定大于配置的项目目录优势,支持多种远程仓库和插件**,侧重于大项目构建**。缺点:学习成本高、资料少、脚本灵活、版本兼容性差等。
劣势:每一个版本都较上一次有非常大的改动,没有做较好向上兼容学习成本高,groovy脚本语言
Whatever:无论哪种项目构建工具,都有自身的优势和劣势,所以选择一款最适合自己的就是最好的。
Gradle是一种开源自动化构建工具,支持多语言环境,受Ant、Maven思想的影响,集二者之大成,相比Ant的不规范,Maven的配置复杂、生命周期限制较多,Gradle既规范也更灵活,可以使用DSL(领域特定语言,如Groovy)编写构建,脚本更加精悍。本课程基于Gradle7
讲解。
Gradle组成
Gradle官网:https://gradle.org/
Gradle官方下载安装教程页面:https://gradle.org/install/
Gradle官方用户手册:https://docs.gradle.org/current/userguide/userguide.html
其中SpringBoot 与Gradle 存在版本兼容问题,Gradle 与Idea 也存在兼容问题,所以考虑到 java 程序员会使用SpringBoot,所以要选择 6.8 版本及高于 6.8 版本的Gradle,那么相应的idea 版本也要升级,不能太老哦。
我们找到我们idea的安装目录,我这里可以看出我要安装7.4
的版本。
具体参考文档
要求Jdk 为 1.8 或者 1.8 版本以上
我这里下的是完整版本
新建GRADLE_HOME环境变量,变量值为将gradle根目录
在path中加入项%GRADLE_HOME%\bin
,类似于JDK或Maven的配置
打开CMD,执行gradle -v
,成功输出版本则表示安装配置完成
接着再配置一个GRADLE_USER_HOME
环境变量,GRADLE_USER_HOME
相当于配置Gradle 本地仓库位置和 Gradle Wrapper 缓存目录
只能叫
GRADLE_USER_HOME
,Gradle本地仓库可以和Maven本地仓库目录一致,我这里就选择maven本地的仓库目录了
Gradle 自带的Maven 源地址是国外的,该Maven 源在国内的访问速度是很慢的,除非使用了特别的手段。一般情况下,我们建议使用国内的第三方开放的Maven 源或企业内部自建Maven 源。
在我们下载的gradle
目录下的init.d
文件夹下有一个readme.txt
的文件
内容如下:
所以我们在init.d 文件夹创建init.gradle 文件,内容如下
其中mavenLocal()表示会先使用本地仓库(前提是配置了M2_HOME环境变量),没有的话就执行下面指定仓库的地址查找。
allprojects {
repositories {
mavenLocal()
maven { name "AlibabaCentral" ; url "https://maven.aliyun.com/repository/central" }
maven { name "AlibabaPublic" ; url "https://maven.aliyun.com/repository/public" }
maven { name "AlibabaGoogle" ; url "https://maven.aliyun.com/repository/google" }
maven { name "AlibabaGradlePlugin" ; url "https://maven.aliyun.com/repository/gradle-plugin" }
maven { name "AlibabaSpring" ; url "https://maven.aliyun.com/repository/spring" }
maven { name "AlibabaCentral" ; url "https://maven.aliyun.com/repository/public" }
maven { name "Bstek" ; url "https://nexus.bsdn.org/content/groups/public/" }
mavenCentral()
}
buildscript {
repositories {
maven { name "AlibabaCentral" ; url "https://maven.aliyun.com/repository/central" }
maven { name "AlibabaPublic" ; url "https://maven.aliyun.com/repository/public" }
maven { name "AlibabaGoogle" ; url "https://maven.aliyun.com/repository/google" }
maven { name "AlibabaGradlePlugin" ; url "https://maven.aliyun.com/repository/gradle-plugin" }
maven { name "AlibabaSpring" ; url "https://maven.aliyun.com/repository/spring" }
maven { name "AlibabaCentral" ; url "https://maven.aliyun.com/repository/public" }
maven { name "Bstek" ; url "https://nexus.bsdn.org/content/groups/public/" }
maven { name "M2" ; url 'https://plugins.gradle.org/m2/' }
}
}
}
拓展 1:启用init.gradle 文件的方法有:
1.在命令行指定文件,例如:gradle --init-script yourdir/init.gradle -q taskName。你可以多次输入此命令来指定多个init文件
2.把init.gradle文件放到 USER_HOME/.gradle/ 目录下
3.把以.gradle结尾的文件放到 USER_HOME/.gradle/init.d/ 目录下
4.以.gradle结尾的文件放到 GRADLE_HOME/init.d/ 目录下
如果存在上面的4种方式的2种以上,gradle会按上面的1-4序号依次执行这些文件,如果给定目录下存在多个init脚本,会按拼音a-z顺序执行这些脚本,每个init脚本都存在一个对应的gradle实例,你在这个文件中调用的所有方法和属性,都会委托给这个gradle实例,每个init脚本都实现了Script接口。
拓展 2:仓库地址说明
mavenLocal(): 指定使用maven本地仓库,而本地仓库在配置maven时settings文件指定的仓库位置。如D:/repository,gradle 查找jar包顺序如下:USER_HOME/.m2/settings.xml >> M2_HOME/conf/settings.xml >> USER_HOME/.m2/repository
maven { url 地址},指定maven仓库,一般用私有仓库地址或其它的第三方库【比如阿里镜像仓库地址】。
mavenCentral():这是Maven的中央仓库,无需配置,直接声明就可以使用。
jcenter():JCenter中央仓库,实际也是是用的maven搭建的,但相比Maven仓库更友好,通过CDN分发,并且支持https访问,在新版本中已经废弃了,替换为了mavenCentral()。
总之, gradle可以通过指定仓库地址为本地maven仓库地址和远程仓库地址相结合的方式,避免每次都会去远程仓库下载依赖库。这种方式也有一定的问题,如果本地maven仓库有这个依赖,就会从直接加载本地依赖,如果本地仓库没有该依赖,那么还是会从远程下载。但是下载的jar不是存储在本地maven仓库中,而是放在自己的缓存目录中,默认在USER_HOME/.gradle/caches目录,当然如果我们配置过GRADLE_USER_HOME环境变量,则会放在GRADLE_USER_HOME/caches目录,那么可不可以将gradle caches指向maven repository。我们说这是不行的,caches下载文件不是按照maven仓库中存放的方式。
拓展 3:阿里云仓库地址请参考:https://developer.aliyun.com/mvn/guide
Gradle 项目默认目录结构和Maven 项目的目录结构一致,都是基于约定大于配置【Convention Over Configuration】。其完整项目目录结构如下所示:
Tips:
- 只有war工程才有webapp目录,对于普通的jar工程并没有webapp目录
- gradlew与gradlew.bat执行的是指定wrapper版本中的gradle指令,不是本地安装的gradle指令哦。
借助于 spring 脚手架创建gradle 第一个项目:https://start.spring.io/
项目内容如下:
# distributionBase和distributionPath是配合使用,指定gradle解压后的存放位置
# GRADLE_USER_HOME表示用户目录,
# windows系统:c:\window\\.gradle\
# linux是$HOME/.gradle
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
# 指定某个版本gradle下载地址,idea插件中规定的版本
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-bin.zip
# zipStoreBase和zipStorePath配合使用,指定下载gradle.zip存放位置
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
这就是依赖项
特别提示 1:使得在Terminal 中执行以gradlew 开头命令和操作图形化的IDEA 使用Gradle 版本不一定是同一个版本。
1.Terminal中以gradlew开头指令用的是Wrapper规定的gradle版本,wrapper中规定版本默认和idea插件中规定的版本一致。
2.而图形化的IDEA使用Gradle是本地安装的哦。
特别提示 2:目前只能是在创建项目时重新设置本地gradle,创建新项目需要重新去改。不像maven可以在创建项目之前就可以默认项目配置
特别提示3:当 我 们 在 gradle.build 文 件 添 加 依 赖 之 后 , 这 些 依 赖 会 在 下 载 到
GRADLE_USER_HOME/caches/modules-2/files-2.1
目录下面,所以这里的GRADLE_USER_HOME
相当于 Gradle 的本地仓库,当然也可以如下方式找到jar 包位置。
常用gradle指令 | 作用 |
---|---|
gradle clean |
清空build目录 |
gradle classes |
编译业务代码和配置文件 |
gradle test |
编译测试代码,生成测试报告 |
gradle build |
构建项目 |
gradle build -x test |
跳过测试构建项目 |
需要注意的是:gradle 的指令要在含有build.gradle 的目录执行
方法 | 描述 |
---|---|
afterEvaluate |
可以添加一个闭包,它会在项目完成评估后立即执行。当执行属于该项目的构建文件时,会通知此类监听器。 |
allprojects |
配置当前项目以及它的每个子项目 |
apply |
应用零个或多个插件或脚本。 |
beforeEvaluate |
添加一个闭包,它会在项目开始评估前立即执行 |
configure |
通过闭包配置对象集合。 |
copy |
复制指定的文件 |
defaultTasks |
设置此项目的默认任务的名称。当开始构建时没有提供任务名称时使用这些。 |
delete |
删除文件和目录 |
exec |
执行外部命令 |
file |
解析相对于该项目的项目目录的文件路径 |
findProject |
按路径定位项目。如果路径是相对的,则相对于该项目进行解释。 |
findProperty |
找特定属性,如果未找到,则返回给定属性的值或 null |
getAllTasks |
返回此项目中包含的任务的地图 |
hasProperty |
确定此项目是否具有给定的属性 |
javaexec |
执行 Java 主类 |
javaexec |
执行外部 Java 进程。 |
mkdir |
创建一个目录并返回一个指向它的文件。 |
property |
返回给定属性的值。此方法定位属性如下: |
setProperty |
设置此项目的属性。此方法在以下位置搜索具有给定名称的属性,并将该属性设置在它找到该属性的第一个位置。 |
subprojects |
配置本项目的子项目 |
task |
创建Task 具有给定名称的 a 并将其添加到此项目中 |
uri |
将文件路径解析为 URI,相对于该项目的项目目录 |
这是用gradle创建的springboot工程的第一种示例:
这种是在我们idea默认的配置项
plugins {
//维护springboot的版本号,不单独使用,和下面的俩个插件一起使用
id 'org.springframework.boot' version '2.7.1'
//类似于maven中的 只做依赖的管理,不做实际依赖
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.zsq'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
repositories {
mavenCentral()
}
dependencies {
//我们前面的插件指定了默认的版本号,做了版本管理,所以我们这可以不用写版本号
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'cn.hutool:hutool-all:5.8.4'
}
tasks.named('test') {
useJUnitPlatform()
}
这是用gradle创建的springboot工程的第二种示例:
buildscript {
repositories {
maven { url 'https://maven.aliyun.com/repository/public' }
}
dependencies {
classpath 'org.springframework.boot:spring-boot-gradle-plugin:2.7.1'
}
}
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
group = 'com.zsq'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
repositories {
mavenCentral()
}
dependencies {
//我们前面的插件指定了默认的版本号,做了版本管理,所以我们这可以不用写版本号
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'cn.hutool:hutool-all:5.8.4'
}
tasks.named('test') {
useJUnitPlatform()
}
buildscript{}
:配置当前gradle脚本自身需要使用的构建信息或依赖buildscript {
repositories {
maven { url 'https://maven.aliyun.com/repository/public' }
}
dependencies {
classpath 'org.springframework.boot:spring-boot-gradle-plugin:2.7.1'
}
}
repositories{}
:仓库配置通过 repositories{} 可以配置maven,ivy,local仓库。这样子,在dependencies{}声明的依赖就可以通过repositories{}中指定的仓库查询到具体的JAR资源。
repositories {
mavenLocal()
mavenCentral()
maven {
// Name is optional. If not set url property is used
name = 'Main Maven repository'
url = 'https://maven.aliyun.com/repository/central'
}
//有权限控制的仓库
maven() {
credentials {
username = 'username'
password = 'password'
}
url = 'https://maven.aliyun.com/repository/central'
}
//本地仓库
repositories {
flatDir(dir: '../lib', name: 'libs directory')
flatDir {
dirs '../project-files', '/volumes/shared-libs'
name = 'All dependency directories'
}
}
}
dependencies{}
:依赖配置在gradle中dependencies{}是一等公民,它描述了configurations{}中分组依赖的第三方资源。我们可以把依赖简单的分成两大类:
//配置依赖
dependencies {
//compile已过时,推荐使用implementation
//按照maven名称加载jar
implementation 'com.google.guava:guava:11.0.2'
//排除部分依赖
implementation('org.slf4j:slf4j-simple:1.6.4') {
exclude 'org.slf4j:slf4j-api'
}
//测试模块
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.4.2'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.4.2'
//依赖其他子项目
implementation project(':projectA')
//加载目录下所有的jar
implementation fileTree(dir: 'libs', include: ['*.jar']) //多个文件
implementation ('com.google.guava:guava:11.0.2'){
//在版本冲突的情况下优先使用该版本
isForce = true
//禁用依赖传递
transitive = false
}
}
//使用dependencis任务可以查看当前依赖树,*表示被忽略的
获取插件的渠道有以下2种
现如今使用评率非常高的几款插件:SpringBoot构建插件,Docker容器集成插件,junit单元测试插件等
script plugins
脚本插件通常是一个脚本,和一个普通的 build.gradle
文件没什么区别 。脚本插件其实并不能算是一个真正的插件,就是一个扩展脚本。但我们不能忽视它的作用,它是脚本模块化的基础。我们可以把复杂的脚本文件,进行分块,分段整理,拆分成一个个职责分明的脚本插件。就像我们平常封装的 Utils 工具类一样,封装一个 utils.gradle 工具脚本。脚本可以存在本地,也可以存在网络上,只需要提供脚本的相对路径或者 URL ,引用方式如下:
//使用本地插件
apply from: './other.gradle'
apply from: this.rootProject.file('other.gradle')
//使用网络远程插件
apply from: 'https://gitee.com/xxx/xx/raw/master/it235.gradle'
binary plugins
我们可以通过二进制插件的ID来应用。插件 ID 是插件的全局唯一标识符或者名字。Gradle中的插件按照来源可以分为核心插件和非核心插件。Gradle 核心插件的特殊之处就在于他们都有一个简短的 ID,例如 Java 插件的是 “java” 。其它非核心二进制插件也必须使用插件ID的完全限定形式(例com.github.foo.bar
)。使用二进制插件的方式有2种,如下。
必须结合buildscript{} 应用插件 ,老版本中使用
//build.gradle中的顶级语句,如下分别是使用java/idea/war/docker插件
apply plugin: 'java'
//apply plugin: JavaPlugin 也可以通过指定插件类来应用,与java效果一样
apply plugin: 'idea'
apply plugin: "war"
//声明
apply plugin: "com.jfrog.bintray"
apply plugin: 'org.akhikhl.gretty'
//buildscript
buildscript {
repositories {
maven {url "https://maven.aliyun.com/repository/public"}
maven { url 'https://maven.aliyun.com/repository/jcenter' }
}
//应用插件
dependencies {
classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.0"
classpath 'org.akhikhl.gretty:gretty:+'
}
}
plugins{} 新写法,这种叫plugins DSL写法,对应的是PluginDependenciesSpec实例
//build.gradle中的顶级语句,声明和应用放在一起
plugins {
//核心插件,gradle提供
id 'java'
id 'eclipse'
id 'war'
//非核心插件(社区插件),必须通过id+version的全限定名的方式进行引用
id 'com.bmuschko.docker-remote-api' version '6.7.0'
//apply false 表示在父项目中声明,但是父项目不会立即加载,可以在子项目中通过ID的方式进行使用
id 'com.jfrog.bintray' version '1.8.5' apply false
}
//注意:plugins暂时不支持第三方插件,如果要使用第三方插件请使用老的写法。同时plugins中不能随意编写其他的语句体
apply false
的使用场景
//settings.gradle,有3个子项目
include 'hello-a'
include 'hello-b'
include 'goodbye-c'
//根项目的build.gradle
plugins {
//apply false 表示根项目不会解析加载,只进行定义和插件的版本管理
id 'com.example.hello' version '1.0.0' apply false
id 'com.example.goodbye' version '1.0.0' apply false
}
//hello-a/build.gradle
plugins {
id 'com.example.hello'
}
//hello-b/build.gradle
plugins {
id 'com.example.hello'
}
//goodbye-c/build.gradle
plugins {
id 'com.example.goodbye'
}
自定义插件
插件自定义包括三个步骤:建立插件工程、配置参数、发布插件与使用插件。
插件的源码可以存放在以下3个地方
build script中
可以直接在build.gradle中编写插件,这样的好处是当前项目能够自动编译和加载,但该插件在构建脚本之外不可见。
class GreetingPlugin implements Plugin<Project> {
void apply(Project project) {
project.task('hello') {
doLast {
println 'Hello from the GreetingPlugin'
}
}
}
}
// Apply the plugin
apply plugin: GreetingPlugin
//使用 gradle -q hello 执行即可
buildSrc project中
您可以将插件的源代码放在以下目录中(不同语言编写用不同的目录)
rootProjectDir/buildSrc/src/main/java
rootProjectDir/buildSrc/src/main/groovy
rootProjectDir/buildSrc/src/main/kotlin
Gradle 将负责编译和测试插件,并使其在构建脚本的类路径中可用。该插件对构建使用的每个构建脚本都是可见的。但是,它在构建之外是不可见的,因此您不能在定义它的构建之外重用插件。
独立项目中
创建一个单独的项目。该项目生成并发布一个 JAR,然后就可以在多个项目中使用该插件,其他开发者也能下载使用。我们一般会在该jar中编写或依赖一些插件,或者将几个相关的任务类捆绑到一起。