Gradle学习笔记
Gradle简介
Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化构建工具。它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置,而不是传统的XML方式。
Gradle的优势
-
依赖管理:即将你项目中的jar包管理起来,你可以使用Maven或者Ivy的远程仓库、或者本地文件系统等(可以和Maven共用仓库)
-
编译打包:可以通过脚本实现花样打包,包括修改文件、添加抑或排除某些类或资源、采用指定JDK版本 构建、打包后自动上传
-
多项目支持:Gradle对多项目有着良好的支持,比如一个很具有代表性的实践就是 Spring Framework(Spring源码就是使用Gradle的!!!)
-
多语言支持:无论是 java、groovy、scala、c++都有良好的支持
-
跨平台支持:gradle是基于jvm的,只要有 jvm 你就可以让gradle运行
构建生命周期
Gradle构建生命周期分为三个阶段:初始化、配置和执行.
初始化阶段
初始化阶段主要是创建Project实例,并加载settings.gradle1文件,加载完setting.gradle文件后,加载在setting.gradle文件中配置的子工程的build.gradle文件。
配置阶段
配置阶段主要是解析settings.gradle文件,加载所有的Project实例,并配置它们之间的依赖关系,生成有向无环树。
执行阶段
执行阶段主要是根据命令行参数,执行相应的任务。按照之前生成的有向无环树,执行相应的任务。
构建脚本
构建脚本是一个Groovy文件,用于定义项目的构建过程。构建脚本中可以使用Groovy语法来定义任务、插件等。[Gradle的配置文件都基于Groovy语法进行编译和运行的,build.gradle文件实际上是实现了一个Project接口,接口中有许多常量以及方法,通过此种方式进行项目配置(个人感觉有点像SpringFrameWork框架的配置类)]
依赖管理
- 本地仓库依赖[Gradle在构建本地仓库时,官方建议不要以本地Maven仓库为原型去加载依赖,而是将本地以来库分开]
- 远程仓库依赖[即使用Maven中心仓库的方式导入依赖]
Gradle的本地依赖库在配置Gradle环境变量的[GRADLE_USER_HOME]变量的目录中的[.gradle\caches\modules-2\files-2.1]文件夹下[即Gradle的本地库]
Gradle的本地仓库中的依赖存储方式和Maven的依赖存储方式不同[Gradle是将依赖的GAV坐标的和jar包进行分开存储,有的依赖的存储方式是存储一个pom.xml文件]
Gradle的配置文件build.gradle常用的属性和方法
Gradle中的Wrapper包装器
简介
Gradle Wrapper是一个用于帮助用户安装和升级Gradle的工具。它是一个包含Gradle安装文件的脚本和一个属性文件,这些文件可以用来下载和安装Gradle,并确保使用的是正确的Gradle版本。
使用
项目中的gradlew
,gradlew.cmd
脚本的作用就是wrapper中规定的gradle版本;
常用命令:
gradlew --gradle-version
用与指定使用的Gradle的版本,修改配置文件中配置的gradle wrapper的版本gradlew --gradle-distribution-url
用于指定下载的Gradle发行版的url下载地址
执行流程
Gradle中的gradle命令和gradlew命令执行的是不同的脚本
- 执行
gradlew
命令时,会首先检查当前目录下是否存在gradle/wrapper/gradle-wrapper.jar
文件。如果存在,则使用该文件中的GradleWrapperMain
类来启动Gradle Wrapper。 GradleWrapperMain
类会读取gradle-wrapper.properties
文件中的配置信息,包括Gradle的版本、下载地址等。- 根据配置信息,下载并安装Gradle;会将下载的Gradle解压到指定的位置目录下[%GRADLE_USER_HOME%目录下的wrapper/dists目录中]。
- 并构建本地缓存[%GRADLE_USER_HOME%目录下cache(缓存)目录中]
- 下载完成后,
GradleWrapperMain
类会使用下载的Gradle版本来执行构建任务。
流程图
GradleWrapper配置文件
gradle-wrapper.properties
文件中包含以下配置信息:
distributionBase
: 指定Gradle发行版的解压位置。distributionPath
: 指定Gradle发行版的解压路径[选购于distributionBase
的路径]。distributionUrl
: 指定Gradle发行版的下载地址。zipStoreBase
: 指定Gradle本地缓存的位置。zipStorePath
: 指定Gradle本地缓存的路径。
Gradle中的任务Task
定义:任务是构建过程中的一个原子操作,它负责执行某个具体的任务,比如编译、打包、测试等。同时,任务还可以依赖于其他任务,形成一个任务依赖图有向无环树。以及可以设置任务的输入和输出,以便在执行任务时传递参数和获取结果。另外在Gradle中还以自定义任务
常见任务 | 任务描述 |
---|---|
gradle build | 构建项目 测试 打包等操作 |
gradle run | 运行一个服务,需要配置application 插件才能正常运行,同时需要配置主启动类 |
gradle clean | 清空当前项目的build [build目录时Gradle项目在构建和准备运行时构建出来的]目录 |
gradle init | 初始化当前Gradle项目 |
gradle wrapper | 用于生成wrapper文件夹 |
gradle wrapper -gradle-version | 升级wrapper 版本号 |
gradle wrapper -distribution-type all | 用于关联源码 |
项目报告相关任务 | 任务描述 |
---|---|
gradle projects | 列出所有项目及所有子项目列表,以层次结构展示出来 |
gradle tasks | 列出当前项目的已分配的任务的列表 |
gradle tasks -all | 列出所选项目所分配的任务列表 |
gradle tasks -group | 显示所选项目中指定分组的任务列表 |
gradle help -task someTask | 显示某个任务的详情信息 |
gradle dependencies | 查看整个项目的依赖信息,以依赖树的方式显示在依赖的后面标注* 表示依赖冲突,Gradle中默认使用高版本的依赖 |
gradle properties | 列出所选项目的属性列表 |
在gradle.properties
文件中,该文件通常配置项目的全局信息
日志选项 | 描述 |
---|---|
-q /-quiet | 表示只记录错误级别的日志 |
-w /-warn | 设置日志级别为warn |
-i /-info | 设置日志级别为info |
-d /debug | 设置日志界别为debug |
Gradle的其余任务 | 描述 |
---|---|
gradle -x task | 指在任务执行中跳过某个任务 |
gradle taskName -return -task | 表示强制执行某个任务 |
gradle taskName -continue | 忽略前面执行的任务,继续执行其余任务;最后统一在任务报告中显示 |
gradle init -type pom | 将Maven项目转换为Gradle项目(在当前Maven项目的根目录中执行) |
Gradle中任务支持驼峰命名方式的缩写执行任务
任务的创建方式
- 使用
task 'taskName'{任务行为}
的方式创建任务[taskName]
Gradle中任务的添加的方式
- Gradle中的Task[任务]底层原理是根据build.gradle的配置文件中任务行为的加载顺序进行添加任务行为,任务行为分为doFirst()和doLast()两种方式
- 配置文件中只声明了一个Task时,任务的执行顺序是 doFirst || action || doLast;
- 当配置文件中包含多个Task时,会根据以上格式进行任务的前置和后置的添加[doFirst的执行顺序是根据先声明的后执行,后声明的先执行的顺序执行,且始终在action前执行;后置任务执行方式与前置相同,且始终在action后执行;]
- Task的声明方式还可以有内部和外部的方式可以直接根据声明的事务的实例使用
.
操作符调用goFirst()方法声明前置任务行为,后置任务行为和前置任务行为的声明方式相同
-
使用Map集合的凡是定义多个任务
def map =new HashMap<String,Object[Closure]> map.put("taskName",{print("任务行为")}) task(map,"allTaskName"){ /* 任务的配置阶段:在配置阶段执行 */ doFirst{ print("前置任务行为") } doLast{ print("后置任务行为") } }
-
使用Gradle提供的Project类的task()方法来创建任务
/* 任务的内部创建方式:在使用此种方式创建任务时,任务的名称在没有歧义的情况下可以不是用引号包裹 */ def myFirstTask=task ("myTask") { /* 任务配置阶段 */ doFirst{ print("前置任务行为") } doLast{ print("后置任务行为") } } /* 任务的外部创建方式 */ myFirstTask.doFirst{ print("前置任务行为") } myFirstTask.doLast{ print("后置任务行为") }
-
调用Tasks类中的register()方法进行任务的定义2
-
使用
tasks.register()
方法创建任务时可以有多种方法重载,可以在方法中传入一个闭包用来指定该任务的执行体[在闭包的定义方式中:闭包作为方法的最后一个参数时可以将闭包作为方法体写入]def taskFirst=tasks.register('taskFirst') { /*任务配置阶段:在Gradle配置阶段生效*/ doFirst { print("前置任务行为") } doLast { print("后置任务行为") } }
-
调用Tasks类中的create()方法进行任务的定义
tasks.create('taskFirst') { /*任务配置阶段:在Gradle配置阶段生效*/ doFirst { print("前置任务行为") } doLast { print("后置任务行为") } }
-
任务的依赖方式
任务之间的依赖关系始终保持被依赖的任务在依赖它的任务之前执行,在Gradle中,任务之间的依赖关系是通过dependsOn
属性来定义
-
参数方式定义依赖
task 'A'{ doLast{ print("任务A") } } task 'B'{ doLast{ print("任务B") } } task 'C'{ doLast{ print("任务C") } } task 'C'(dependsOn :['B','C']){ doFirst{ print("任务C") } doLast{ print("任务C") } }
-
任务的内部依赖
task 'A'{ doLast{ print("任务A") } } task 'B'{ doLast{ print("任务B") } } task 'C'{ dependsOn=['A','B'] doLast{ print("任务C") } }
-
任务的外部依赖
task 'A'{ doLast{ print("任务A") } } task 'B'{ doLast{ print("任务B") } } task 'C'{ doLast{ print("任务C") } } C.dependsOn=['A','B']
-
跨项目之间的任务依赖定义方式(只需要在人物的名称前加上项目名称;联合
:
)task ':projectName:A'{ doLast{ print("任务A") } } task ':projectName:B'{ doLast{ print("任务B") } } task ':projectName:C'{ doLast{ print("任务C") } } C.dependsOn=[':projectName:A','projectName:B']
定义任务时指定属性
配置项 | 描述 | 默认值 |
---|---|---|
type | 基于一个存在的Task 创建,和继承相似 | DefaultTask |
overwrite | 是否替换一个已经存在的Task ,通常搭配type 一起使用 | false |
dependOn | 用于配置任务的依赖 | [] |
action | 添加到任务中的一个Action 或一个闭包 | null |
description | 用于配置任务的描述 | null |
group | 用于配置任务的分组 | null |
enable | 直接设置任务的开启 | true |
timeOut | 任务的超时属性,任务超时是会抛出超时异常,并标记为任务执行失败,并且会影响后面任务的执行 | 永不超时 |
在定义任务时也可以给任务分配属性:定义任务的时候可以直接指定任务属性,也可以给已有的任务动态分配属性
任务之间执行脚本的依赖关系
任务类型
常见任务类型 | 任务类型的作用 |
---|---|
Delete | 删除文件或目录 |
Copy | 将文件复制到指定目录,同时在复制的同时还可以重命名和筛选文件 |
CreateStartScript | 创建启动脚本 |
Exec | 执行命令行进程 |
GenerateMavenPom | 生成Maven 模块描述符文件 |
GradleBuild | 构建Gradle |
Jar | 组装JAR 归档文件 |
JavaCompile | 编译Java 源文件 |
JavaDoc | 生成Java 的Doc 文档 |
Tar | 组装Tar 存档文件,即打包成Linux 压缩文件 |
War | 打包成War 包 |
Test | 执行单元测试,并生成报告 |
Upload | 将Configuration 的构建上传到一组存储库 |
Zip | 打包为Zip 文件 |
PublishToMavenRepository | 将MavenPublication 发布到MavenArtifactRepostal |
依赖的类型3
依赖类型 | 描述 |
---|---|
compileOnly | 用于标识在编译期需要但是不需要在项目打包的时候使用的依赖 |
runtimeOnly | 只在运行时有效,而在编译时期不需要使用的依赖 |
implementation | 针对在src/main 下的项目代码,标识在编译和运行时期都有效的依赖 |
testCompileOnly | 在单元测试包下使用,用于标识编译测试是需要的依赖 |
testRunTimeOnly | 在单元测试包下使用,用于标识在单元测试包运行时需要的依赖 |
testImplementation | 在单元测试包下使用,用于标识在src/main 和src/test 包下的编译和测试需要的依赖 |
provideCompile | war 插件提供支持,编译测试阶段代码需要依赖的jar 包,而在运行阶段容器已经提供相应的支持,不需要将这些jar 包和项目代码一起打包成war 包 |
api | java-library 插件提供支持,这些依赖可以传递性的导出给使用者,用于测试和编译时期 |
compileOnlyApi | java-library 插件提供支持,这些依赖可以传递性的导出给使用者,只在编译时期需要,在运行时不需要 |
任务的查找,规则,断言以及默认任务[本质上是任务的属性]
表达式 | 描述 |
---|---|
tasks.findByName("taskName") | 根据任务名称查找 |
tasks.findByPath | 根据相对路径查找 |
tasks.addRule('Message',Closure closure) | 表示给任务添加规则,当任务执行失败是不会报错,二是输出给定的提示信息,Message 表示提示信息,后面的闭包作任务的提示的行为 |
tasks.OnlyIf | 表示当前任务只有在满足指定的条件或者包含特定属性时才执行,通过gradle taskName -P message 进行任务的断言 |
defaultTask 'taskName...' | 使用外部定义的方式指定默认的任务 |
api
和implementation
的区别
api | implementation | |
---|---|---|
编译时 | 能进行依赖传递,底层变;全部要改变,编译速度下降 | 不行进行以来的传递,底层改变;不用全部改变,编译速度块 |
运行时 | 运行时会加载,所有的class 模块都会被加载 | 运行时会加载,所有模块的class 都要被加载 |
应用场景 | 适用于多模块依赖,避免重复依赖模块 | 多数情况下都会使用implementation |
Gradle中插件的应用
在Gradle中,插件分为两类:脚本插件和二进制插件。脚本插件本质上是一个脚本文件,然后在build.gradle文件中使用apply()方法来应用插件。二进制插件实现了Plugin接口的类,可以自定义Gradle的行为,比如自定义任务、扩展属性、自定义任务类型等。同时在Gradle官方文档中,Gradle插件分为核心插件和第三方插件4
插件的分类
- 脚本插件:脚本插件本质上是一个脚本文件[脚本文件中通常用来定义一些扩展方法、任务,键值对等],然后在build.gradle文件中使用apply()方法来应用插件
- 二进制插件(对象插件):实现了
Plugin<Project>
接口的类,可以自定义Gradle的行为,比如自定义任务、扩展属性、自定义任务类型等。[接口的泛型需要指定] - 自定义插件:需要实现
Plugin<Object/Project>
接口,并重写apply()方法,在apply()方法中可以进行插件的配置,比如添加任务、添加扩展属性等。
一 脚本插件5
-
构建脚本插件
tasks.register('hello') { println "${company}" + "${message.compileSdkVersion}" + "${spring.version}" }
-
引入插件6
apply from: 'version.gradle'
二 对象插件[又叫二进制插件]
-
核心插件[内部插件] 4
-
Map键值对的方式引入
apply plugin: 'java' apply plugin: 'application' apply plugin: 'org.spring.boot'
-
使用
PluginsDSL
的方式引入apply { plugin 'java' }
-
-
第三方插件7
-
原始方式8
buildscript { ext { springBootVersion = '2.6.3' } repositories { mavenCentral() mavenLocal() maven { url "https://repo.spring.io/plugins-release" } } dependencies { classpath "org.springframework.boot:spring-boot-gradle-plugin:+" } } apply plugin: 'org.springframework.boot'
-
使用
PluginsDSL
方式引入9plugins { id 'org.springframework.boot' version '2.6.3' }
-
三 自定义插件10
在使用自定义插件的时候,可以在实现Plugin<Project>
接口的类中重写apply()
方法,在apply()
方法中可以进行插件的配置,比如添加任务、添加扩展属性等。并且在该类中可以进行该插件的属性的扩展,已完成更多个任务的配置。
-
使用类继承
Plugin<Object>
接口的方式进行自定义插件的编写abstract class MyPluginExtension implements Plugin<Object> { /* 自定义属性 */ abstract Property<String> getMessage() /* 构造方法 */ MyPluginExtension() { message.convention("Hello Plugin") } } class MyPlugin implements Plugin<Project> { void apply(Project target) { /* 获取Project的扩展容器对象:第一个参数是插件的ID值,第二个参数是扩展的类型[可以使 用自定义的类型] */ def extension = target.extensions.create('greeting', MyPluginExtension) target.tasks.register('hello') { print extension.message.get() } } } /* 引入插件 */ apply plugin: MyPlugin /* 配置插件的属性赋值 */ greeting.message = 'Hello Gradle' /* 在项目根目录下的命令行中启动任务 */ /* gradle -q hello */
-
使用自定义接口的方式进行自定义插件的扩展与编写
interface MyPluginExtension { /* 自定义属性 */ Property<String> getMessage() Property<String> getCompileSdkVersion() Property<String> getSpringVersion() } class MyPlugin implements Plugin<Project> { void apply(Project target) { def extension = target.extensions.create('greeting', MyPluginExtension) /* 使用传入的参数创建任务:即给传入的类创建任务,即为插件 */ target.tasks.register('hello') { /* 在调用扩展的属性是默认调用属性的修改器 */ print extension.message.get() } } } /* 扩展的类或者接口中有多个属性的情况下可以使用闭包的方式进行属性的赋值操作 */ greeting{ message = 'Hello Plugin' compileSdkVersion = '30' spring.version = '5.3.1' } /* 在项目根目录下的命令行中启动任务 */ /* gradle -q hello */
BuildSrc项目
BuildSrc目录是Gradle的默认插件目录,在编译Gradle的时候会自动识别这个目7录,将其中的代码编译为一个插件;目的是是的当前工程的其他模块可以引用项目自定义的插件
-
创建BuildSrc项目步骤(只可在本项目中访问)
-
首先建立一个名为buildSrc的javaModule,将buildSrc从setting.gradle中的include modules 标签移除,只保留项目中的build.gradle和src/main目录,其余全部删除;名字必须要是buildSrc
-
修改创建模块的build.gradle文件如下
apply plugin: 'groovy' apply plugin: 'maven-publish' dependencies{ /* 以下两个都是必须的 */ implementation gradleApi() implementation localGroovy() } repositories{ /* 配置中央以及远端库 */ google() jcenter() mavenCentral() } /* 将项目入口设置为:src/main/groovy|java */ sourcesSets{ main{ groovy{ srcDirs = ['src/main/groovy'] } } }
-
在groovy/java目录下创建一个类,并实现
Plugin<Project>
接口,在apply()方法中可以进行插件 的配置,比如添加任务、添加扩展属性等。 -
在项目的resources目录下创建META-INF/gradle-plugins目录,在该目录下创建一个名为
com.example.buildSrc.properties
的文件,文件内容如下<!-- 键是固定的,值是自定义插件的全类名--> implementation-class=com.example.buildSrc.MyPlugin
-
引入插件
/* 在想要引入插件的项目的build.gradle文件中进行插件引入的声明:学如resources目录下插件配置文件的中的配置对应插件的值,即为该插件的全类名 */ apply plugin: 'com.example.buildSrc'
-
-
创建BuildSrc项目步骤(可被其他项目访问)
-
首先建立一个名为buildSrc的javaModule,只保留项目中的build.gradle和src/main目录,其余全部删除;与第一种不同的是,这种创建方式保留了setting.gradle中的include modules标签.
apply plugin: 'groovy' apply plugin: 'maven-publish' dependencies{ /* 以下两个都是必须的 */ implementation gradleApi() implementation localGroovy() } repositories{ /* 配置中央以及远端库 */ google() jcenter() mavenCentral() } /* 将项目入口设置为:src/main/groovy|java */ sourcesSets{ main{ groovy{ srcDirs = ['src/main/groovy'] } } } /* Maven仓库的配置信息 */ publishing{ publications{ myLibrary(MavenPublication){ /* 指定GAV坐标 */ groupId = 'com.example' artifactId = 'my-library' version = '1.0.0' /* 发布JAR包 */ from components.java /* 发布WAR包 */ from components.war } } repositories{ maven{ url = uri('build/repo') /* url "$rootDir/lib/release" */ } /* 发布项目到Maven私服中 */ maven{ /* name属性可选,表示仓库名称,url必填/7发布地址:可以是本地仓库或者maven 私服//url = layout.buildDirectory dir("repo") */ name = 'myRepo' url = uri('http://localhost:8081/repository/maven-releases/') /*change URLs to point to your repos,e.g.http://my.org/repo//认证 信息:用户名和密码*/ credentials{ username='' password='' } } } }
-
刷新Gradle构建的插件,后会在项目中生成一个
lib
目录,同时会依照以上配置的GAV
坐标生成目录机构,在目录结构中有一个plugin
目录 -
同时,在
Gradle
项目构建插件下会生成对应插件的一些指令,包括将插件发布到Maven私服中,以及将插件发布到本地仓库中等命令 -
在其他项目中使用该插件,需要在目标项目中的build.gradle文件中进行插件引入的声明
buildscript{ repositories{ maven{ url "$rootDir/lib/release" } dependencies{ classpath 'pluginId:my-library:version' } } } /* 是在定义插件的时候定义的插件ID */ apply plugin: 'pluginId'
-
在项目名根目录下执行命令
gradle build
看到自定义的输出,即表示插件生效(注:buildscript
标签一定要在apply
标签之前声明)
-
Gradle的Gretty插件
Gretty插件可以用来启动一个本地服务器,并可以指定端口号,是Gradle内置的一个插件
Gretty插件的使用与配置[仅限于低于Gradle7以下的版本]
-
引入Gretty插件
<!-- 使用DSL的方式定义插件 --> plugins{ id 'war' id 'org.gretty' version '2.1.1' }
-
指定Maven仓库
respositories{ <!-- 指定中仓库 --> jcenter() <!-- 指定Maven本地仓库 --> mavenCentral() }
-
Gretty插件的配置
httpPort=8888 <!-- 项目名 --> contextPath="/web" debugPort=5005 debugSuspend=true httpEnabled=true managedClassReload=true httpsPort=4331 <!-- 底层的Servlet容器 :默认是Jetty服务器 --> servletContainer='tomcat8'
-
运行Gretty插件
<!-- 执行命令 --> gradle appRun
Gradle对于测试的支持
Gradle支持多种测试框架,如JUnit、Spock、TestNG等,在Gradle中,使用test
任务来执行测试,当执行build
或者test
任务时,Gradle会自动执行test
目录下的测试类,并生成一份测试报告[在build目录下]
单元测试的其余配置
test{
<!-- 开启使用测试开关 -->
enabled(true)
<!-- 在使用Junit5是需要加 -->
useJUnitPlatform()
<!-- 包含那个测试包 -->
include('com.example.demo.test')
<!-- 排除那个测试包 -->
exclude('com.example.demo.test')
}
Gradle中JAVA插件常用的属性
属性名称 | 类型 | 默认值 | 描述 |
---|---|---|---|
reportsDirName | String | reports | 生成报告的名称 |
reportsDir | File(只读) | buildDir/reportsDirName | 生成报告的目录 |
testResultDirName | String | test-result | 生成测试result.xml文件的目录名称 |
testResultDir | File(只读) | reportsDir/testReportDirName | 生成测试报告的目录 |
libsDirName | String | libs | 生成lib库的名称 |
libsDir | File(只读) | buildDir/libsDirName | 生成lib库的目录 |
distsDirName | String | distributions | 生成发布文件的目录名称 |
distsDir | File(只读) | buildDir/distsDirName | 生成发布文件的目录 |
docsDirName | String | docs | 生成帮助文档的目录名称 |
docsDir | File(只读) | buildDir/docsDirName | 生成帮助文档的目录 |
dependencyCacheDirName | String | dependency-cache | 存储缓存依赖信息的目录名称 |
dependencyCacheDir | File(只读) | buildDir/dependencyCacheDirName | 存储缓存资源依赖信息的目录 |
sourceSets | SourceSetContainer(只读) | Not null | 包含工程的资源集合(sourcesets.) |
sourceCompatibility | JavaVersion(字符串或数字) | 根据使用的JVM决定 | 编译Java文件是指定使用的java版本 |
targetCompatibility | JavaVersion(字符串或数字) | sourceCompatibility | 生成的字节码文件的java版本 |
archivesBaseName | String | projectName | 作为归档文件的默认名称(即达成jar包或者war包) |
Gradle中对于文件的操作
通过本地文件的方式
/* Gradle中的文件操作时调用Project.file()方法来获取文件对象,然后调用File[实际上是Java中的File类]的方法来操作文件。 */
def file = file('filePath')
file.createNewFile()
通过文件集合的方式
/* 使用Gradle中的files()方法获取一个FileCollection对象,方法的参数可以传一个数组或者多个文件的路径 */
FileCollection collection = files('filePath1', 'filePath2')
/* forEach()方法需要一个Consumer对象作为参数,这个接口是一个函数式接口,因此可以使用Lambda表达式的方式进行传参,然后就可以对FileCollection中的每个文件进行操作 */
collection.forEach {
item ->
println(item.name)
item.delete()
}
/* 在Gradle中对于Collection集合形式的对象可以使用 as 关键字将该集合转换为集合 */
Set set = collection as Set
List list = collection as List
set.forEach { item -> item.createNewFile() }
/* Gradle中Set集合可以使用+或-运算符来对集合进行合并或差集运算 */
set + files('filePath3')
set - files('filePath2')
通过文件树的方式
/* 使用文件树的方式对文件进行操作 */
FileTree tree = fileTree(["$file", "filePath"])
/* 文件树的访问器 */
tree.visit(new FileVisitor() {
@Override
void visitDir(FileVisitDetails dirDetails) {
print dirDetails.getName()
}
@Override
void visitFile(FileVisitDetails fileDetails) {
def inputStream = fileDetails.open()
InputStream stream = inputStream.newObjectInputStream()
}
})
通过文件拷贝的方式
/* 使用Project.copy()方法来复制文件,然后调用CopySpec[实际上是org.gradle.api.file.CopySpec接口]的方法来配置复制行为 */
copy {
/* 以下两个方法是CopySpec的两个方法,用于配置复制行为 */
from("filePath")
/* 拷贝压缩包:会将压缩包中的内容拷贝到目标目录中,并不是直接拷贝压缩包 */
from(zipTree('filePath'))
into("filePath")
/* 还可以对文件进行过滤的操作 */
include('**/*.java')
include({ String fileName ->
fileName.concat('txt')
})
exclude('**/Test.java')
rename { String fileName, String extension
-> fileName.replace('oldName', 'newName') + extension
}
}
/* 创建任务的形式进行文件的操作 */
tasks.register('copyFile', Copy) {
/* 以下两个方法是CopySpec的两个方法,用于配置复制行为 */
from("filePath")
/* 拷贝压缩包:会将压缩包中的内容拷贝到目标目录中,并不是直接拷贝压缩包 */
from(zipTree('filePath'))
into("filePath")
/* 还可以对文件进行过滤的操作 */
include('**/*.java')
include({ String fileName ->
fileName.concat('txt')
})
exclude('**/Test.java')
rename { String fileName, String extension
-> fileName.replace('oldName', 'newName') + extension
}
}
通过文件归档的方式
/* 对文件进行归档的操作 */
tasks.register('archiveFile', Zip) {
from("filePath")
into("filePath")
archiveBaseName="archiveName"
}
/* 获取压缩包的情况下可以使用Project.tarTree()或zipTree()方法来获取压缩包的FileTree对象 */
tarTree("filePath || fileName")
zipTree("filePath || fileName")
Gradle中项目或第三方依赖的依赖的方式以及依赖冲突管理
在gradle.build文件中使用dependencies {}进行依赖的引入和管理:本质上是Project.dependencies()方法
-
依赖的引入
dependencies { /* 本地依赖文件和文件树 */ implementation files('filePath') implementation fileTree(dir: 'filePath', includes: ['*.jar'], excludes: ['*.txt']) /* 项目依赖:':'表示相对路径,':projectName'表示项目依赖[项目之间的依赖需要保证项目在 settings.gradle文件中被声明] */ implementation project(':projectName') /* 直接依赖:简写的情况下就是平差导入依赖的写法,可以省略属性名称,中间使用`:`隔开 ||依赖 的本质是DependencyHandler.add()方法的调用,返回值是一个Dependency对象,可以指定依赖的 group,name,version,configuration等属性 */ implementation group: 'groupId', name: 'artifactId', version: 'version', components: 'java' }
-
本地依赖
dependencies { /* 本地依赖文件和文件树 */ implementation files('filePath') implementation fileTree(dir: 'filePath', includes: ['*.jar'], exclude: ['*.txt']) }
-
项目依赖
dependencies { /* 项目依赖:':'表示相对路径,':projectName'表示项目依赖[项目之间的依赖需要保证项目 在 settings.gradle文件中被声明] */ implementation project(':projectName') }
-
直接依赖
dependencies { /* 直接依赖:简写的情况下就是平差导入依赖的写法,可以省略属性名称,中间使用`:`隔开 ||依赖 的本质是DependencyHandler.add()方法的调用,返回值是一个Dependency对象,可以指定依赖的 group,name,version,configuration等属性 */ implementation group: 'groupId', name: 'artifactId', version: 'version', components: 'java' }
-
-
依赖冲突的管理以及解决方案
-
在Gradle中如果发生依赖的冲突,Gradle的默认解决方案是使用更高版本的那个依赖
-
使用
exclude
标签的方式解决dependencies { implementation project(':projectName'){ /* 方法使用一个闭包作为参数,同时可以使用属性进行依赖的精确管理和指定传递 */ exclude group: 'groupId', module: 'moduleName' } }
-
禁用依赖传递
dependencies { implementation project(':projectName'){ /* 不见已使用 */ transitive = false } }
-
强制使用某个版本
dependencies { /* 在指定项目的build.gradle文件中的依赖后加上 !! 表示强制使用 */ implementation 'org.springframework.boot:spring-boot-starter-web!!' implementation ('org.springframework.boot:spring-boot-starter-web'){ version{ /* + 号表示使用最新版本 */ strictly '+' } } }
-
Groovy学习
Groovy简介
Groovy是一种面向对象的编程语言
Groovy是一种基于JVM的敏捷开发语言,它结合了Python、Ruby和Smalltalk的许多特性。Groovy 代码可以与Java代码自由交互。Groovy 代码被编译成Java字节码,所以它可以被任何已安装的Java虚拟机执行。Groovy 代码可以在运行时被动态解释。Groovy 字节码可以被静态地编译成Java字节码,使其可以直接被虚拟机执行,而不需要先进行解释。
Groovy的语法特性
在Groovy中,语句的结束符号可以省略,同时调用方法时的参数在没有歧义的情况下可以省略小阔号;方法的返回值也可以不需要显示的声明,在多行代码中,Groovy会默认将最后一行代码作为方法返回值返回;
-
对象属性赋值和取值
-
对象
.
属性名=属性值 || [对象的取值方式与之相同]def user=new User() user.age=12
-
对象[“属性名”]=属性值 || [对象的取值方式与之相同]
def user=new User() user.["age"]=12
-
对象的
set
方法[Groovy中] || [对象的取值方式与之相同]def user=new User() user.setAge(12) user.setProperty("name","李四")
-
具名构造器的方式[由Groovy提供]
/* new User("属性名":"属性值","属性名":"属性值") */ def user = new User("name": "张三", "age": 20)
-
类和脚本的混合使用
一 Groovy脚本的定义
- 在Groovy中如果一个.groovy文件中没有定义类,那么这个文件将作为脚本使用[脚本中不需要使用main方法即可运行],同时作为脚本的
.groovy
文件编译为字节码文件后,默认继承String类 - Groovy中的类和脚本可以相互调用,并且Groovy中类和脚本可以混合,即:在Groovy中一个Groovy文件中可以同时声明类和脚本,此时不要在定义一个和文件名相同的类,否则会报错
Groovy类的定义
-
Groovy中类的定义和Java相同,但是和Java不同的时,Groovy中属性的
get
和set
方法可以省略,Groovy中内置类属性的get
和set
方法 -
Groovy中的默认的方法,类以及属性的访问修饰符默认为
public
;Groovy的访问修饰符有public
,private
,protected
三种访问修饰符 -
Groovy中类的属性默认是使用
private
进行修饰的,Groovy中属性的赋值方式除了使用set
方法,还可以使用对象的变量名调用setProperty("propertyName","propertyValue")
的方式进行赋值;相对的,和get
方法有相同的作用的getProperty("propertyName")
方法可以获取到对象中的指定属性的值 -
Groovy类中默认引用了如下包,因此你不需要显示的引入这些包
import java.lang.* import java.util.* import java.io.* import java.net.* import groovy.lang.* import groovy.util.* import java.math.BigInteger import java.math.BigDecimal
Groovy中的异常处理机制
-
Groovy中的异常处理机制和Java相同,都是使用
try-catch-finally
语句块进行异常处理 -
在Groovy中,可以使用
tru-with-resources
进行IO方面的操作try (def inputStream = new FileInputStream("input.txt"), outputStream = new FileOutputStream("output.txt")) { inputStream.copyTo(outputStream) } catch (IOException exception) { exception.getMessage() exception.printStackTrace() }
Groovy的构造方法
- Groovy中构造方法使用具名构造器的方式定义[Groovy类自带的]
- Groovy中构造方法和Java相同,可以进行不同参数类型的构造方法的重载
变量
数据类型 | 所占字节数[相对于bit 位] | 名称 | 定义方式 |
---|---|---|---|
byte | 1个字节 | 字节类型 | byte b=20 |
short | 2字节 | 短整型 | short s=20 |
int | 4字节 | 整形 | int i=20 |
long | 8字节 | 长整型 | long l=40L |
float | 4字节 | 单精度浮点 | float f=20.5f |
double | 8字节 | 双精度浮点 | double d=30.5 |
char | 2字节 | 字符 | char c='a' |
boolean | [在JVM中]1字节 | 比尔类型 | boolean result=true/false |
String | 不详 | 字符串类型 | String word='常量' &"可使用${variable}进行字符串拼接"/' &'''可以换行的字符串''' |
-
变量声明:
- 在
Groovy
中官方推荐使用def
关键字来声明变量,并且变量名可以省略var
关键字,同时在Groovy中变量的定义使用了类型推断,因此定义变量时不需要声明类型 - 在
Groovy
中定义变量仍旧可以使用具体的数据类型定义变量 Groovy
中变量的赋值和Java中一样,可以进行简单的运算;并使用=
符进行赋值
- 在
-
变量引用:
- 在
Groovy
中,可以使用${variable}
进行变量的引用;同时在不引起歧义的情况下,可以省略{}
符号直接进行变量的引用 - 在
Groovy
中,和Java
中引用变量的方式相同
- 在
-
String类型声明
-
Groovy
中声明String类型的方式有三种 -
''
单引号引用的表示字符串常量 -
""
双引号引用的表示可以使用${}
或正常的字符串拼接 -
'''字符串'''
三引号引用的表示可以换行的字符串String word='''这是一个字符串 可以直接换行'''
-
Groovy中的运算符
-
算术运算符:
+
,-
,*
,/
,%
-
关系运算符:
==
,!=
,>
,<
,>=
,<=
-
逻辑运算符:
&&
,||
,!
-
位运算符:
运算符 描述 &
表示与运算 |
表示或运算符 ^
表示按未 异或
运算符~
表示按为反运算符 -
范围运算符:
3...10
表示由3
到10
的连续数字 -
赋值运算符:
运算符 表达式 描述 +=
A+=B
等价于A=A+B
两个变量相加 -=
A-=B
等价于A=A-B
两个变量相减 *=
A*=B
等价于A=A*B
两个变量相乘 /=
A/=B
等价于A=A/B
两个变量相除 %=
A%=B
等价于A=A%B
两个变量取余 -
Groovy中的特殊符号
?.
,11def user=new User() <!-- 属性访问:如果对象为null,则不会抛出NullPointerException异常,而是返回null --> user?.name <!-- 调用方法:如果对象为null,则不会执行方法调用,而是返回null --> user?.getName() <!-- 链式调用:可以链式地使用安全导航符,访问对象的属性或调用方法,如果链中任何一个对象为null,则整个链式调用会返回null --> user?.name?.toUpperCase()
Groovy中的闭包
-
闭包是Groovy语言的核心,闭包是Groovy语言中的一种特殊语法,它允许将函数作为参数传递
/* 定义一个没有参数的闭包 */ def closure={name->println "Hello,${name}!"} /* 调用闭包 */ closure.call("$variable") closure("$variable")
-
闭包的参数列表中可以没有参数
/* 定义一个没有参数的闭包 */ def closure={println "Hello,World!"} /* 调用闭包 */ closure.call() closure()
-
闭包的参数列表中可以有多个参数
/* 定义一个有多个参数的闭包 */ def closure={paramsOne,paramsTwo->println "Hello,World!"} /* 调用闭包 */ closure.call() closure()
-
当闭包作为方法的最后一个参数是,可以将闭包作为方法的方法体进行简写
def callback={paramsOne,paramsTwo->println "Hello,World!"} /* 定义一个方法 */ def calculate(num1,num2,Closure closure){ print("运行前") closure.call() print("运行后") } /* 调用方法(当闭包作为方法的最后一个参数是,可以将闭包作为方法的方法体进行简写) */ calculate(num1,num2{num1,num2->print($num1+$num2)}) calculate(num1,num2){num1,num2->print($num1+$num2)}
-
当闭包作为方法的最后一个参数时,并且该方法只有一个参数时,可以省略参数列表的小括号[且闭包的默认参数叫
it
]def callback={it->println "Hello,World!"} /* 调用闭包 */ callback()
- 当闭包作为方法的最后一个参数时,并且该方法只有一个参数时,可以省略参数列表的小括号[且闭包的默认参数叫`it`]
```groovy
def callback={it->println "Hello,World!"}
/* 调用闭包 */
callback()
一个项目中只会有一个settings.gradle文件,用于配置所有项目。且每个setting.gradle都是一个Groovy脚本,在脚本中可以定义多个Project实例。 ↩︎
延迟创建任务,在创建任务时,任务不会立即创建,而是等到任务被依赖或者被执行时才会创建 ↩︎
类似于Maven中依赖坐标的
<scope>
标签,用于标识依赖的作用域 ↩︎Gradle自带的插件,比如java插件、application插件等,这些插件的源码都在org.gradle.api.plugins包下 ↩︎ ↩︎
脚本插件本质上是一个脚本文件[脚本文件中通常用来定义一些扩展方法、任务,键值对等],然后在build.gradle文件中使用apply()方法来应用插件 ↩︎
在build.gradle文件中使用apply()方法来引入插件,插件的引入方式有两种:1.通过插件ID引入,2.通过插件类引入 ↩︎
通过
MavenCentral``GradlePlugin
,Portal
等仓库下载的插件,这些插件的源码都在org.gradle.plugin.xxx包下;buildScript标签必须要在所有的apply标签之前,否则会导致插件的引入失败 ↩︎使用ext用来在插件中增加用户自定义属性;同时用户自定义属性无论是在那个项目中都是可以被访问到的 ↩︎
使用此种方式的插件需要在Gradle的插件仓库中发布,然后在build.gradle文件中通过id来引入 ↩︎
定义一个类,需要实现
Plugin<Object>
接口,并重写apply()方法,在apply()方法中可以进行插件的配置,比如添加任务、添加扩展属性等。 ↩︎安全导航符(Safe Navigation Operator),通常用
?.
表示,用于简化对可能为null的对象进行属性访问或方法调用的操作,以避免NullPointerException异常的抛出[调用时不会抛出NPE
(NullPointException)]而时将该调用返回空。 ↩︎