Gradle
项目结构
|-build # 封装编译后的字节码、打成的包Jar、War,测试报告等信息
|-gradle# 封装包装器文件夹
| |-wrapper
| |-gradle-wrapper.jar
| |-gradle-wrapper.properties
|_src
| |-main
| |-test
|-build.gradle 构建脚本
|-gradlew 包装器启动脚本,执行wrapper中gradle的指令
|-gradlew.bat 包装器启动脚本,执行wrapper中gradle的指令
|-settings.gradle 设置文件,定义项目及子项目名称信息,和项目是一一对应关系
- http://start.spring.io 创建springboot项目
常用指令
指令 | 作用 |
---|---|
gradle clean | 清空build目录 |
gradle classes | 编译业务代码和配置文件 |
gradle test | 编译测试代码,生成测试报告 |
gradle build | 构建项目 |
gradle build -x test | 跳过测试构建项目 |
gradle 的指令要在含有 build.gradle 的目录执行
修改maven下载源
在gradle的init.d目录下创建以.gradle
结尾的文件,.gradle
文件可以实现在build开始之前执行
allprojects {
repositories {
mavenLocal()
maven {name "Alibaba" ; url "https://maven.aliyun.com/repository/public"}
maven {name "Bstek" ; url "https://nexus.bsdn.org/content/groups/public/"}
mavenCentral()
}
buildscript {
repositories {
maven {name "Alibaba" ; 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/"}
}
}
}
启动 init.gradle 文件的方法
-
在命令行指定文件;
gradle --init-script dir/init.gradle
可以多次输入此命令指定多个init文件 -
把
init.gradle
文件放到 USER_HOME/.gradle/ 目录下 -
以
.gradle
结尾的文件放到 GRADLE_HOME/.gradle/init.d/ 目录下 -
以
.gradle
结尾的文件放到 GRADLE_HOME/init.d/ 目录下如果存在以上4中方式的2种以上,会按上面的1~4序号依次执行这些文件,如果给定目录下存在多个 init 脚本,会按拼音 a~z 顺序执行,每个 init 脚本都存在一个对应的gradle实例,在这个文件中调用的所有方法和属性,都会委托给这个 gradle 实例,每个 init 脚本都实现了 Script 接口
仓库地址
mavenLocal()
使用maven本地仓库,本地仓库在配置maven时 settings 文件指定的仓库位置,gradle查找jar包顺序如下:USER_HOME/.m2/setings.xml—>M2_HOME/conf/settings.xml—>仓库地址repositirymaven{url 地址}
指定maven仓库mavenCentral()
maven中央仓库
本地maven仓库没有依赖,会到配置的仓库远程下载。但是下载的jar不是存储在本地maven仓库,而是放在自己的缓存目录,默认 USER_HOME/.gradle/caches目录,如果配置过 GRADLE_USER_HOME环境变量,则会放在 GRADLE_USER_HOME/caches 目录下
阿里云仓库 https://developer.aliyun.com/mvn/guide
Wrapper 包装器
Gradle Wrapper 是对 Gradle 的一层包装,用于解决实际开发中可能会遇到的不同的项目需要不同版本的Gradle问题
有了 Gradle Wrapper 本地可以不用配置Gradle ,下载Gradle项目后,使用gradle项目自带的wrapper即可
-
项目中 gradlew、gradlew.bat 脚本用的是wrapper中规定的gradle版本
-
gradle指令用的是本地的gradle,所以gradle指令和gradlew指令所使用的版本有可能不一样,两者使用方式一致,只不过把gradle指令换成gradlew指令
-
适应gradlew指令时,指定一些参数来控制Wrapper的生成
--gradle-version
指定使用的gradle版本gradle wrapper --gradle-version=7.4.2
升级wrapper版本号,只是修改gradle.properties中的wrapper版本,未实际下载
--gradle-distribution-url
用于指定下载Gradle发行版的url地址
-
GradleWrapper执行流程
- 第一次执行 ./gradle build 命令时,gradle会读取 gradle-wrapper.properties文件的配置信息
- 准确的将指定版本的 gradle 下载并解压到指定的位置GRADLE_USER_HOME 目录下的wrapper/dists目录中
- 并构建本地缓存GRADLE_USER_HOME目录下caches目录中,下次再使用相同版本的gradle就不用下载了
- 之后执行的 ./gradlew 所使用命令都是使用的指定的gradle版本
-
gradle-wrapper.properties 文件
-
# 下载的gradle压缩包解压后存储的 主目录 distributionBase=GRADLE_USER_HOME #相对于distributionBase的解压后的gradle压缩包的路径 distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip # 下载的gradle的压缩包的 存储主目录 zipStoreBase=GRADLE_USER_HOME # 压缩包相对 zipStoreBase 的存储路径 zipStorePath=wrapper/dists
-
GRADLE_USER_HOME 环境变量用于 gradle wrapper 下载的特定版本的 gradle 存储目录,如果没有配置过 GRADLE_USER_HOME 环境变量 ,默认在当前用户家目录下的 ./gradle文件夹中
Gretty 部署项目
-
支持 tomcat、jetty 等 Servlet 容器
-
支持项目热部署、HTTPS、调试
-
引入插件
plugins{ id 'war' id 'org.gretty' version '2.2.0' } //Gretty插件配置 gretty{ httpPort=8080 contextPath='/web' debugPort=5005//default debugSuspend=true//default managedClassReload=true//修改类之后重新加载 servletContainer='tomcat8'//默认使用的是jetty9服务器,支持tomcat7/8 httpsEnabled=true //支持https httpsPort=4431 }
-
执行Gretty插件
gradle appRun
-
官方文档:http://akhikhl.github.io/gretty-doc/Gretty-configuration.html
对测试的支持
测试任务自动检查并执行测试源集中的所有单元测试,测试执行后会生成一个报告,支持JUNIT 和 TestNG 测试
测试报告在 build/reports 目录下
-
对Junit5.x版本支持
dependencies { testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0' } test { enabled=true//执行测试,false构建跳过测试 useJUnitPlatform()//支持Junit5 include 'com/aa/**' // 只执行com/aa 下的测试 exclude 'com/aa/bb/**' //排除com/aa/bb 下的测试 }
在 build.gradle 目录下执行
gradle test
指令,gradle就会执行所有加了@Test注解的测试,并生成测试报告
Gradle 项目生命周期
Initialization–>configuration–>execution
- Initialization 初始化项目构建
- 执行 GRADLE_USER_HOME/init.gradle init script 初始化操作,如配置仓库、用户名、密码等
- 执行 settings.gradle 初始化一次构建所参与的所有模块
- configuration 加载项目中所有模块的Build Script,根据脚本创建对应的task,最终根据所有task生成 Task 组成的有向无环图
- 执行 build.gradle ,先加载根目录下的构建脚本,在加载子目录下的构建脚本
- execution 根据上阶段构建的有向无环图,按顺序执行
settings 文件
在项目初始化阶段确定一下引入哪些工程,需要加入到项目构建中,为构建项目工程树做准备
- 内容:主要定义了当前gradle 项目及子project的项目名称
- 位置:必须在根目录下
- 文件名:settings.gradle
- 对应实例:org.gradle.api.initialization.Settings 实例,每个项目只有一个settings文件
- 只需要关注文件中的 include方法,使用相对路径引入工程,
:
代表项目分割符,如果以:
开头,则表示相对于 rootProject
//根目录项目名
rootProject.name = 'Gradle_Demo'
//包含子工程名称
include 'project1'
//包含的子工程下的工程名称
include 'project1:subproject1'
Task
项目实质上是Task对象的集合,一个Task表示一个逻辑上较为独立的执行过程,比如编译Java源代码,拷贝文件,打包Jar文件,甚至可以是执行一个系统命令,另外一个Task 可以读取和设置Project的Property已完成特定的操作
文档:https://docs.gradle.org/current/userguide/tutorial_using_tasks.html
task task1 {
// 任务配置段:配置阶段执行
println '配置任务 task1'
// 任务行为:执行阶段执行,doFirst 会在 doLast 执行之前执行
doFirst {
println 'dofirst'
}
doLast {
println('dolast')
}
}
根目录下执行gradlew task1
- 无论是定义任务自身的action还是添加的doFirst、doLast方法,其实底层都被放入到一个Action的List中,最初这个action List 是空的,当我们设置了action任务自身的行为,它先将action添加到列表中,此时列表中只有一个action,后续执行doFirst的时候doFirst在action前面添加,执行doLast的时候doLast在action后面添加(有多个doFirst、doLast时,最后添加的doFirst在最前面,最后的doLast在最后面),最后这个List形成doFirst、doSelf、doLast 的执行顺序
任务的依赖关系
dependsOn
- 参数依赖
task a{
doLast {
println('Task a')
}
}
task b{
doLast {
println('Task b')
}
}
// 参数方式依赖, dependsOn 后面用 :
task c(dependsOn:['a','b']){
doLast {
println('Task c')
}
}
- 内部依赖
task a{
doLast {
println('Task a')
}
}
task b{
doLast {
println('Task b')
}
}
task c{
dependsOn=['a','b']
doLast {
println('Task c')
}
}
- 外部依赖
task a{
doLast {
println('Task a')
}
}
task b{
doLast {
println('Task b')
}
}
task c{
doLast {
println('Task c')
}
}
c.dependsOn=['a','b']
- task可以跨项目依赖
- 一个task依赖多个task时,被依赖的task之间如果没有依赖关系,那么它们的执行顺序是随机的
- 重复依赖的任务只会执行一次
任务定义方式
-
通过Project 中的 task() 方法
//方式一 task ('A',{ println 'A' }) //方式二 task ('B'){ println 'B' } //方式三 task C{ println 'C' } //方式四 def map = new HashMap<String,Object>(); map.put("action",{println 'D'}) task(map,'D')
-
通过 tasks 对象的 create 或者 register 方法
tasks.create('E'){ println 'E' } //regists 执行的是延迟创建,只有当task被需要使用的时候才会被创建 tasks.register('F'){ println 'F' }
定义任务的同时指定任务的属性,也可以给已有的任务动态分配属性
配置项 | 描述 | 默认值 |
---|---|---|
type | 基于一个存在的Task来创建,和类继承相似 | DefaultTask |
overwrite | 是否替换存在的Task,与type配合使用 | false |
dependsOn | 配置任务的依赖 | [] |
action | 添加到任务中的一个Action或者闭包 | null |
description | 配置任务的描述 | null |
group | 用于配置任务的分组 | null |
task(group: 'atguign',description: '这是任务A','A')
task H{
group('atguign')
description '这是任务H'
}
task F{}
F.group="atguign"
clean.group('atguign')//给已有的clean任务重新指定组信息
任务类型
常见任务类型 | 任务作用 |
---|---|
Delete | 删除文件或目录 |
Copy | 将文件复制到目标目录中,可以在复制时重命名和筛选文件 |
CreateStartScripts | 创建启动脚本 |
Exec | 执行命令进程 |
GenerateMavenPom | 生成Maven模块描述符POM文件 |
Jar | 组装Jar文件 |
War | 组装War文件 |
JavaCompile | 编译Java源文件 |
Javadoc | 为Java类生成HTMLAPI文档 |
Test | 执行JUnit或者TestNG测试 |
PublishToMavenRepository | 将MavenPublication发布到mavenartifactrepostal |
Upload | 将Configuration的构建上传到一组存储库 |
GradleBuild | 执行Gradle构建 |
Tar | 组装Tar存档文件 |
Zip | 组装ZIP归档文件,默认是压缩ZIP的内容 |
task A(type:Delete){
// Delete 的两个属性
delete 'file'//删除file文件
followSymlinks(true)
}
-
自定义Task类型
class CustomTask extends DefaultTask{ //@TaskAction 表示Task本身要执行的方法 @TaskAction def doSelf(){ println 'Task 自身在执行的 in doSelf' } } def myTask = task MyTask(type:CustomTask) myTask.doFirst { println('task doFirst') } myTask.doLast { println('task doLast') } //执行 gradlew MyTask 输出 //task doFirst //Task 自身在执行的 in doSelf //task doLast
任务执行顺序
三种方式指定 Task 执行顺序
dependsOn
强依赖方式- 通过 Task 输入输出
- 通过 API 指定执行顺序
https://docs.gradle.org/current/dsl/org.gradle.api.Task.html
动态分配任务
一旦注册了任务,就可以通过API访问它们
//注册四个任务
4.times {counter->
tasks.register("task$counter"){
doLast{
println("$counter")
}
}
}
//通过api访问任务0;任务0 强依赖任务2、任务3
//构建4个任务,任务2、任务3 需要在 任务0 之前优先加载
tasks.named('task0'){
dependsOn('task2','task3')
}
任务的关闭与开启
每个任务都有一个 enabled
默认是true,将其设置为 false 阻止执行任何任务动作,禁用的任务将标记为“跳过”
task a{
doLast {
println('a')
}
enabled(true)//显示设置任务开启,默认是true
}
a.enabled=false//设置任务关闭
任务超时
每个任务都有一个 timeout 可用于限制执行的时间属性,当任务达到超时时,其任务执行线程将被中断,该任务将被标记为失败,终结器任务仍将运行。如果 --continue 使用,其他任务可以在此之后继续执行。不响应中断的任务无法超时。Gradle 的所有内置任务均会及时响应超时
task A{
doLast {
Thread.sleep(1000)
println('任务A')
}
//500毫米超时
timeout= Duration.ofMillis(500)
}
task B{
doLast {
println('任务B')
}
}
// 执行 gradlew A B A超时,抛出异常,B没有执行
// 执行 gradlew A B --continue A抛出异常,B继续执行
任务查找
task A{
doFirst {
println('doFirst 1')
}
}
//根据任务名查找,只能找当前文件中的任务,不可跨项目
tasks.findByName('A').doFirst {println('doFirst 2')}
tasks.findByName('A').doFirst {println('doFirst 3')}
//根据任务相对路径查找,可以跨项目 :表示相对于根目录
tasks.findByPath(':A').doFirst {println('doFirst 4')}
//输出 4 3 2 1
任务规则
执行、依赖一个不存在的任务时,gradle 会执行失败,报错误信息,改进成不报错,打印提示信息
task Hello{
doLast {
println('Hello')
}
}
tasks.addRule("规则描述,方便调试"){
String taskName->task(taskName){
doLast {
println("该 $taskName 任务不存在!!!")
}
}
}
// gradlew aaa Hello
// aaa 不存在也不会报错,Hello 任务照常执行
任务 onlyIf 断言
Task 有一个 onlyIf 方法,接收一个闭包作为参数,如果该闭包返回true则该任务执行,否则跳过
控制哪些情况打什么包,什么时候执行单元测试等
task Hello{
doLast {
println('Hello')
}
}
// 通过 -P 为Project 添加 指定属性
// gradlew Hello -P aaa
Hello.onlyIf {!project.hasProperty('aaa')}
默认任务
gradle 允许定义一个或者多个在没有指定其他任务时执行的默认任务
// 声明为默认任务,只要执行grade命令,默认任务就会执行
defaultTasks('Hello','World')
tasks.register('Hello'){
doLast{
println('Default Hello')
}
}
tasks.register('World'){
doLast{
println('Default World')
}
}
tasks.register('other'){
doLast{
println('other')
}
}
文件操作
本地文件
使用 Project.file(java.lang.Object) 方法,创建的 File 对象就是Java中的File对象。通过指定文件相对路径或绝对路径来对文件操作,相对路径为相对当前project的目录
//使用相对路径
File configFile = file('src/conf.xml')
configFile.createNewFile()
//使用绝对路径
configFile = file('D:\\conf.xml')
configFile.createNewFile()
//使用一个文件对象
configFile = new File('src/config.xml')
configFile.createNewFile()
文件集合
文件集合就是一组文件的列表,we年集合用 FileCollection 接口表示,可以使用 Project.files(java.lang.Object) 方法来获取一个文件集合对象
def collection = files('src/a.xml', new File('src/b.xml'), 'src/c.xml')
collection.forEach() {
it.createNewFile()
println it.name
}
// 文件结合转成Set类型
Set set1 = collection.files
Set set2 = collection as Set
//文件集合转List
List list = collection as List
for (item in list) {
println(item.name)
}
// 添加 或者 删除 一个集合
def union = collection + files('src/d.xml')
union.forEach(){
println(it.name)
}
def minus = collection - files('src/d.xml')
minus.forEach({println(it.name)})
文件树
文件数是有层级结构的文件集合,一个文件树可以代表一个目录结构或者ZIP压缩包中的内容结构。
文件树是从文件集合继承过来的,文件树具有文件集合的所有功能
//使用路径创建问价树对象,同时指定包含的文件
ConfigurableFileTree tree = fileTree('src/mian').include('**/*.java')
tree.forEach({println(it.name)})
文件拷贝
使用Copy任务来拷贝文件。可以过滤指定拷贝内容,能对文件进行重命名操作等。Copy任务必须指定一组需要拷贝的文件和拷贝的目录
task Hello(type : Copy){
// CopySpec.from(java.lang.Object) 指定原文件
// 参数不存在,会被忽略
// 参数是目录时,拷贝目录下所有文件,目录本身不会被拷贝
from 'src'
// 参数是文件时,拷贝文件到指定目录
from 'gradle/wrapper/gradle-wrapper.properties'
// 参数是ZIP压缩文件,该压缩文件中内容会被拷贝到指定目录,解压缩
from 'a/a.zip'
// CopySpec.into(java.lang.Object) 指定目标目录
into 'src/main/'
// 拷贝符合条件的文件
include('*.xml')
// 排除其中某些文件
exclude('c.*')
// 拷贝时重命名文件
rename {String name->
name.replace('xml','yaml')
}
}
直接使用 Project.copy(org.gradle.api.Action) 方法
copy {
from('src/a.xml')
into('src/main/')
}
// 执行 gradlew build 即可
归档文件
项目打包成 war、Jar、Zip、Tar 包,使用 Zip、Tar、Jar、War、Ear 任务来实现
apply(plugin:'java')
version('1.0')
task myJar(type:Jar){
from('src/mian')
into('build')
//指定打包后的包名
baseName('demo')
}
//打印包名
println(myJar.archiveName)
依赖
/**
* 依赖方式:
* 本地依赖:依赖本地的某个jar包,可通过 文件集合、文件树的方式指定
* 项目依赖:依赖某个project
* 直接依赖:依赖的类型 依赖的组名:依赖的名称:依赖的版本号
*
* 依赖下载:
* 当执行 build 命令时,gradle会去配置的依赖仓库中下载对应的Jar
*/
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
// 直接依赖
implementation 'org.apache.logging.log4j:log4j-spring-cloud-config-client:2.17.2'
implementation group: 'org.apache.logging.log4j', name: 'log4j-spring-cloud-config-client', version: '2.17.2'
// 本地依赖,通过文件集合
implementation files('lib/mysql.jar')
// 本地依赖,通过文件树
implementation fileTree('dir': 'lib', includes: ['*.jar'], excludes: ['mysql.jar'])
// 项目依赖,被依赖的文件名一定要在settings.gradle文件中存在
implementation project(':webproject')
}
依赖的类型 | 说明 |
---|---|
compileOnly | 由java插件提供,适用于编译期需要而不需要打包的情况 |
runtimeOnly | 由java插件提供,运行期需要,编译期不需要的情况 |
implementation | 由java插件提供,针对源码"src/main"目录,在编译、运行时都有效 |
testCompileOnly | 由java插件提供,只在测试编译期需要,而测试运行不需要 |
testRuntimeOnly | 由java插件提供,只在测试运行时需要,而测试编译期不需要 |
testImplementation | 由java插件提供,针对源码"src/test"目录,在测试编译、运行时都有效 |
providedCompile | 由War插件提供,编译测试阶段代码需要依赖此jar包,而运行阶段容器已经提供了相应的支持,所以无需将这些文件打入war包中 |
api | 由java-library插件提供,这些依赖项可以传递性地导出给使用者,用于编译时和运行时 |
compileOnlyApi | 由java-library插件提供,声明模块和使用者在编译时需要的依赖项,但在运行时不需要 |
- java插件提供的功能,java-library插件都提供
api 与 implementation 区别
api | implementation | |
---|---|---|
编译时 | 能进行依赖传递,底层变,全部都要变、编译速度慢 | 不能进行依赖传递,底层变,不用全部都要变,编译速度快 |
运行时 | 运行时会加载,所有模块的class都要被加载 | 运行时会加载,所有模块的class都要被加载 |
景 | 适用于多模块依赖,避免重复依赖模块 | 多数情况下使用implementation |
依赖冲突解决
B-->log4j 1.4.2
/
/
ProjectA
\
\
C-->log4j 2.2.4
A、B、C都是本地项目module,log4j 是远程依赖
编译时:B用1.4.2,C用2.2.4,B和C之间没有冲突
打包时:只有一个版本的代码打包进入最终的A对应的包中,这里就有冲突了
- 依赖冲突时,默认情况下,gradle 会使用其中最新版的 jar 包
- 使用exclude移除一个依赖,不允许依赖传递,强制使用某个版本
//移除依赖
dependencies {
implementation('org.heibernate:hibernate-core:3.6.1.Final'){
// 排除某个库(slf4j)依赖,三种写法
exclude(group:'org.slf4j')
exclude(module:'slf4j-api')
exclude(group:'org.slf4j',module:'slf4j-api')
}
// 排除后,使用手动引入
implementation('org.slf4j:slf4j-api:1.4.0')
}
//不允许依赖传递
dependencies {
implementation('org.heibernate:hibernate-core:3.6.1.Final') {
// 不允许依赖传递,一般不用
transitive(false)
}
// 排除后,使用手动引入
implementation('org.slf4j:slf4j-api:1.4.0')
}
//强制使用
dependencies {
implementation('org.heibernate:hibernate-core:3.6.1.Final')
// !! 强制使用1.4.0版本
implementation('org.slf4j:slf4j-api:1.4.0!!')
}
dependencies {
implementation('org.heibernate:hibernate-core:3.6.1.Final')
// 强制使用1.4.0版本
implementation('org.slf4j:slf4j-api:1.4.0'){
version({strictly('1.4.0')})
}
}
dependencies {
implementation('org.heibernate:hibernate-core:3.6.1.Final')
// +/latest.integration 动态版本声明,使用中心仓库中最新版本,不建议用
implementation('org.slf4j:slf4j-api:+')
//implementation('org.slf4j:slf4j-api:latest.integration')
}
//当遇到版本冲突,立即构建失败
configurations.all() { Configuration configuration ->
configuration.resolutionStrategy.failOnVersionConflict()
}
插件
- 可以添加任务到项目中,从而帮助完成测试、编译、打包等
- 可以添加依赖配置到项目中
- 可以向项目中拓展新的属性、方法等
- 可以对项目进行一些约定,如应用java插件后,约定src/main/java目录是源代码的位置,编译时编译这个目录下的java源代码
脚本插件
本质就是一个脚本文件,使用时通过 apply from: 将脚本加载进来,脚本可以是本地文件也可以是网络上的文件
//vsersion.gradle文件
//ext 拓展
ext{
// key=value
company='脚本'
//key=Map
cfgs=[jdk:'11']
spring=[version:'2.2.0']
}
//build.gradle 文件
//'version.gradle' 可以是本地地址,也可以是网络地址
apply from:'version.gradle'
task Hello{
doLast {
println("company $company JDK版本:$cfgs.jdk spring版本$spring.version")
}
}
对象插件
对象插件就是实现了 org.gradle.api.Plugin 接口的插件,每个插件都有一个 plugin id
gradle内部插件使用
/**
* apply(map具名参数方式)
* key:plugin
* value: 插件id/插件的全类名/插件的简类名
*/
apply plugin:'java'
//apply plugin:'JavaPlugin'
//apply plugin:'org.gradle.api.plugins.JavaPlugin'
apply{
plugin 'java'
}
第三方插件
- 使用第三方插件,一般需要配置对应的仓库和类路径
//这个要放在最前面
buildscript {
ext{
springBootVersion='2.3.3.RELEASE'
}
//配置仓库
repositories {
mavenLocal()
maven {url 'http://maven.aliyun.com/nexus/content/groups/public'}
}
//引入插件
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
//应用插件
//社区插件,需要事先引入,不必写版本号
apply {plugin:'org.springframework.boot'}
- 如果第三方插件已经托管在 https://plugins.gradle.org 网站上,可以直接使用
plugins{
id 'org.springframework.boot' version '2.4.1'
}
用户自定义插件
- 只能在当前project中使用
class GreetingPlugin implements Plugin<Project>{
void apply(Project project){
project.task('hello'){
doLast {
println('Hello from the GreetingPlugin')
}
}
}
}
apply plugin:GreetingPlugin
- 在其他项目中使用
buildSrc 是Gradle 默认的插件目录,编译Gradle的时候会自动识别这个目录,将其中代码编译为插件
首先建立一个buildSrc 的javaModule,将 buildSrc 从 included 从 included modules 移除,重新构建,然后只保留 build.gradle 和 src/mian 目录,其他全部删除掉,注意名字一定是 buildSrc ,不然会找不到插件
修改 build.gradle 中的内容
apply plugin:'groovy'//必须
apply plugin:'maven-publish'
dependencies {
implementation(gradleApi())//必须
implementation(localGroovy())//必须
}
repositories {
google()
mavenCentral()//必须
}
//项目入口设置为 src/main/groovy
sourceSets{
main{
groovy{
srcDir 'src/main/groovy'
}
}
}
创建入口目录,在 src/main 下创建代码入口目录
|--buildSrc
|--src
|--main
|--groovy
|--com
|--xxx
|--Test
|--resources
|--META-INF
|--gradle-plugins
|--*.properties任何以.properties结尾的文件
实现插件代码 Test.groovy
package com.xxx
import org.gradle.api.Plugin
import org.gradle.api.Project
class Test implements Plugin<Project>{
@Override
void apply(Project project){
project.task('hello'){
doLast {
println('自定义 Plugin')
}
}
}
}
在 *.properties 文件中指出实现插件的全类名
implementation-class=com.xxx.Test
使用,在module引入写的插件 apply plugin:‘.properties文件的文件名’
- 插件上传maven仓库
将上面写好的插件, buildSrc 文件夹复制一份,修改名称,并把复制的这个 include 到根项目下settings.gradle 中
修改build.gradle文件
apply plugin: 'groovy'//必须
apply plugin: 'maven-publish'
dependencies {
implementation(gradleApi())//必须
implementation(localGroovy())//必须
}
repositories {
google()
mavenCentral()//必须
}
//项目入口设置为 src/main/groovy
sourceSets {
main {
groovy {
srcDir 'src/main/groovy'
}
}
}
publishing {
publications {
//myLibrary 组件名称,随便写
myLibrary(MavenPublication) {
//指定GAV坐标信息
groupId = 'com.xxx.plugin'
version = '1.0'
from components.java//发布jar包
// from components.web//引入war插件,发布war包
}
}
repositories {
//当前项目目录下
maven { url "$rootDir/lib/release" }
//
maven {
// name 属性可选,表示仓库名称 url 必填
name = 'myRepo'
// 本地maven
url = layout.buildDirectory.dir("repo")
// 发布到maven私服
// url = 'http://xxxx'
// 认证信息:用户名和密码
// credentials {
// username = ""
// password = ""
// }
}
}
}
找到对应模块的publishing,点击 publish 发布
按照第三方插件使用方式使用
插件的分析使用
- 插件的引入
- 主要的功能(任务)
gradlew tasks
查看加入某个插件前后的区别 - 工程目录结构;有的插件对目录结构有约束,可以通过属性修改
- 依赖管理方式;不同插件提供不同的依赖管理
- 插件的常用属性
build.gradle文件
-
gradle 的构建脚本文件
-
每个project都会有一个 build.gradle 文件,该文件是项目构建的入口,可配置版本、插件、依赖库等
-
每个build文件都有一个对应的 Project 实例,对 build.gradle 文件配置,本质是设置 Project 实例的属性和方法
-
在 root project 中可以获取到所有的 child project ,可以对 child project 统一配置
-
build中常用属性/方法
-
plugins{ id 'java' id 'maven-publish' } rootProject.name='demo' 项目名称,在settings.gradle 文件中 group 'com.xxx' 项目分组 version '1.0' 项目版本 sourceCompatibility=11 源码JDK版本 targetCompatibility=11 生成class文件的JDK版本 compileJava.options.encoding='UTF-8' 源码解码字符集 compileTestJava.options.encoding='UTF-8' 测试解码字符集 //编译java文件时采用utf-8,源码的编码字符集 tasks.withType(JavaCompile){ options.encoding('UTF-8') } tasks.withType(Javadoc){ options.encoding('UTF-8') } buildscript {} 获取依赖插件 apply() 应用插件 task() 定义任务 plugins{} 应用插件 dependencies {}设置项目依赖 repositories {}设置项目仓库 allprojects {} 设置所有project信息 subprojects {}设置子模块的信息 sourceSets {}设置项目的源代码文件集合 publishing{}配置发布插件 configurations {}配置此项目的依赖项配置 artifacts {} 配置此项目的已发布构件 //对单个project进行配置 project('project名称、路径'){} ext{}//添加自定义属性
-
-
ext配置用户自定义属性,而gradle.properties中一般定义 系统属性、环境变量、项目属性、JVM相关配置信息,该文件中的属性会自动在项目运行时加载
#设置此参数主要是编译下载包会占用大量的内存,可能会内存溢出 org.gradle.jvmargs=-Xms4096m -Xmx8182m #开启gradle缓存 org.gradle.caching=true #开启并行编译 org.gradle.parallel=true #启用新的孵化模式 org.gradle.configureondemand=true #开启守护进程 org.gradle.daemon=true
项目发布
plugins{
id 'maven-publish'//必须插件,maven发布插件
id 'java-library'//带源码和Javadoc发布
}
javadoc.options.encoding='UTF-8'
java{
//生成文档包
withJavadocJar()
// 生成源码包
withSourcesJar()
}
publishing {
publications{
demoProject(MavenPublication){
// 指定GAV坐标信息
groupId='com.aaaa.xxx'
artifactId='xxxx'
version='1.0'
//发布jar包
from components.java
}
}
repositories {
// 本地仓库位于USER_HOME/.m2/repository
mavenLocal()
// 发布项目到私服
maven {
// 发布地址可以是本地仓库或者私服
// url = layout.buildDirectory.dir('repo')
// url='http://xxxx.xxx'
credentials{
username=''
password=''
}
}
}
}
生命周期
- 钩子函数
// 1 初始化阶段 settingsEvaluated
gradle.settingsEvaluated {
println('1、初始化阶段')
}
// 2 初始化阶段 projectsLoaded
gradle.projectsLoaded {
println('2、初始化阶段')
}
def projectName = ''
gradle.addProjectEvaluationListener(new ProjectEvaluationListener() {
// 3.执行各个 project 的 beforeEvaluate :在配置阶段完成
@Override
void beforeEvaluate(Project project) {
projectName = project.named
println("3 $projectName beforeEvaluate")
}
// 5.执行各个 project 的 afterEvaluate :在配置阶段完成
@Override
void afterEvaluate(Project project, ProjectState projectState) {
println("5 $project.name afterEvaluate")
}
})
//4.执行各个 project 的 beforeProject :在配置阶段完成
gradle.beforeProject {
println("4 $projectName beforeProject")
}
//6 执行各个 project 的 afterProject :在配置阶段完成
gradle.afterProject {
println("6 $projectName afterProject")
}
// 7 所有工程的 build.gradle 执行完毕后,回调 Gradle 对象的 projectsEvaluated 方法:在配置阶段完成
def rootProjectName = rootProject.getName()
gradle.projectsEvaluated {
println("7 $rootProjectName projectsEvaluated")
}
//8 配置阶段完毕后 回调 TaskExecutionGraph 对象的 whenReady 方法:在配置阶段完成
gradle.taskGraph.whenReady {
println("8 $rootProjectName taskGraph.whenReady")
}
//9 在当前 Task 执行前,会回调 TaskExecutionGraph 对象的 beforeTask 方法:在执行阶段完成
gradle.taskGraph.beforeTask {
task->
println("$task.name $task.getProject().name")
}
//10 在当前 Task 执行后,会回调 TaskExecutionGraph 对象的 afterTask 方法:在执行阶段完成
gradle.taskGraph.afterTask {
task->
println("$task.name $task.getProject().name")
}
//11 当所有 Task 执行完毕后,会回调 Gradle 对象的 buildFinished:在执行阶段完成
gradle.buildFinished {
println("$rootProjectName")
}
创建SpringBoot项目
-
build.gradle
plugins{ id 'org.springframework.boot' version '2.3.7.RELEASE'//用以维护springboot版本号 id 'io.spring.dependency-management' version '1.0.10.RELEASE'//只做依赖的管理,不做实际依赖 //上面两个一起使用 id 'java' } group 'com.xxx' version '1.0' repositories { mavenLocal() } dependencies { implementation('org.springframework.boot:spring-boot-starter-web ') }
-
如果要管理 org.springframework.boot 和 io.spring.dependency-management 的版本则要用 spring-boot-gradle-plugin 插件
buildscript { repositories { maven {url 'https://maven.aliyun.com/repository/public'} } dependencies { classpath('org.springframework.boot:spring-boot-gradle-plugin:2.4.1') } } apply plugin:'org.springframework.boot' apply plugin:'io.spring.dependency-management' apply plugin:'java' group 'com.xxx' version '1.0' repositories { mavenLocal() } dependencies { implementation('org.springframework.boot:spring-boot-starter-web ') }
-