gradle学习笔记
- 一、下载安装配置环境变量
- 二、使用gradle管理spring项目
- 1、创建项目
- 2、导入项目至编辑器
- 3、打包部署
- 4、将maven项目转为gradle项目
- 三、gradle介绍
- 1、常用命令
- 2、Gradle Wrapper包装器
- 3、gradle进阶说明
- 4、gradle插件
- 四、Groovy 简介
参考博客:https://www.yuque.com/youyi-ai1ik/emphm9/kyhenl?
一、下载安装配置环境变量
1、官网下载地址:gralde官网下载,推荐下载complete完整版,包括了gradle源码和说明文档
2、解压
3、环境变量配置,打开用户变量
- 新建 GRADLE_HOME:E:\Gradle\gradle-7.4
- 编辑path,添加 %GRADLE_HOME%\bin
- 新建GRADLE_USER_HOME:C:\Users\EDZ.m2\repository(
这里推荐与maven仓库保持一致,但是gradle下载的依赖和maven的存放格式都不一样,依赖包在:GRADLE_USER_HOME\caches\modules-2\files-2.1目录下,可以自行查看区别
)
4、监测版本:gradle -v
5、配置镜像
在安装目录下的init.d文件夹里创建init.gradle文件
粘贴以下内容:
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/' }
}
}
}
二、使用gradle管理spring项目
1、创建项目
1、方式一:创建spring项目地址:spring.io,或者阿里云镜像网站:start.aliyun.com
2、方式二:使用cmd命令gradle创建
2、导入项目至编辑器
将创建好的gradle项目导入java工程编辑器,我这里选择的是eclipse2019,idea版本太低了,老是报错,导入截图如下:
导入成功并启动后:
补充:build.gradle还可以做一下优化改动,使用spring-boot-gradle-plugin插件统一管理plugins中org.springframework.boot的版本,配置如下:
原配置:
plugins {
id 'java'
id 'org.springframework.boot' version '2.7.16' //维护springboot版本号,不单独使用,和下面两个插件一起用
id 'io.spring.dependency-management' version '1.0.15.RELEASE' //类似于maven中的<dependencyManagement>标签,只做依赖的管理,不做实际依赖
}
group = 'com.furenqiang'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '1.8'
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
插件版本同一管理配置,org.springframework.boot会和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.furenqiang'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '1.8'
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
3、打包部署
执行build指令
在下面目录可生成jar包
在下面目录生成测试报告
4、将maven项目转为gradle项目
gradle init --type pom
:将maven 项目转换为gradle 项目(根目录执行)
三、gradle介绍
1、常用命令
需要注意的是:gradle 的指令要在含有build.gradle 的目录执行。
比如:
1、编译业务代码和配置文件
会生成build目录
2、gradle test 编译测试代码,生成测试报告
2、Gradle Wrapper包装器
Gradle Wrapper 实际上就是对 Gradle 的一层包装,用于解决实际开发中可能会遇到的不同的项目需要不同版本的 Gradle
问题。例如:把自己的代码共享给其他人使用,可能出现如下情况:
- 对方电脑没有安装 gradle
- 对方电脑安装过 gradle,但是版本太旧了
-
这时候,我们就可以考虑使用 Gradle Wrapper 了。
这也是官方建议使用 Gradle Wrapper 的原因。实际上有了 Gradle Wrapper 之后,我们本地是可以不配置 Gradle 的,下载Gradle 项目后,使用 gradle 项目自带的wrapper 操作也是可以的。 -
那如何使用Gradle Wrapper 呢?
项目中的gradlew、gradlew.cmd脚本用的就是wrapper中规定的gradle版本。参见源码
而我们上面提到的gradle指令用的是本地gradle,所以gradle指令和gradlew指令所使用的gradle版本有可能是不一样的。
gradlew、gradlew.cmd的使用方式与gradle使用方式完全一致,只不过把gradle指令换成了gradlew指令。 -
当然,我们也可在终端执行 gradlew 指令时,指定指定一些参数,来控制 Wrapper 的生成,比如依赖的版本等,如下:
-
具体操作如下所示 :
gradle wrapper --gradle-version=4.4:升级wrapper版本号,只是修改gradle.properties中wrapper版本,未实际下载
gradle wrapper --gradle-version 5.2.1 --distribution-type all :关联源码用 -
那什么时候选择使用 gradle wrapper、什么时候选择使用本地gradle?
下载别人的项目或者使用操作以前自己写的不同版本的gradle项目时:用Gradle wrapper,也即:gradlew。什么时候使用本地gradle?新建一个项目时: 使用gradle指令即可。
3、gradle进阶说明
为了让大家快速的入门gradle,本章将从整体构建脚本的角度介绍:
● 什么是 setting 文件,它有什么作用?
1、作用:主要是在项目初始化阶段确定一下引入哪些工程需要加入到项目构建中,为构建项目工程树做准备。
2、工程树:gradle中有工程树的概念,类似于 maven 中的project 与module。
3、内容:里面主要定义了当前 gradle 项目及子 project 的项目名称
4、位置:必须放在根工程目录下。
5、名字:为settings.gradle 文件,不能发生变化
6、对应实例:与org.gradle.api.initialization.Settings 实例是一一对应的关系。每个项目只有一个settings 文件。
7、关注:作为开发者我们只需要关注该文件中的include 方法即可。使用相对路径【 : 】引入子工程。
8.一个子工程只有在setting 文件中配置了才会被 gradle 识别,这样在构建的时候才会被包含进去。案例如下所示:
//根工程项目名
rootProject.name = ‘root’
//包含的子工程名称
include ‘subject01’
include ‘subject02’
include ‘subject03’
//包含的子工程下的子工程名称
include ‘subject01:subproject011’
include ‘subject01:subproject012’
项目名称中 “:” 代表项目的分隔符, 类似路径中的 “/”. 如果以 “:” 开头则表示相对于 root project 。
然后 Gradle 会为每个带有 build.gradle 脚本文件的工程构建一个与之对应的 Project 对象。
● 说明什么是build 文件,它又有什么作用?
分析一下gradle项目的依赖,Gradle 中的依赖分别为直接依赖,项目依赖,本地jar 依赖。案例如下,以下配置都是写在build.gradle文件里面:
dependencies {
//①.依赖当前项目下的某个模块[子工程]
implementation project(‘:subject01’)
//②.直接依赖本地的某个jar文件
implementation files(‘libs/foo.jar’, ‘libs/bar.jar’)
//②.配置某文件夹作为依赖项
implementation fileTree(dir: ‘libs’, include: [‘*.jar’])
//③.直接依赖
implementation ‘org.apache.logging.log4j:log4j:2.17.2’
注意,如果后面2.17.2不是具体版本号而是一个+号或者“lastest.integration”,表示的是maven中心仓库最新版本号
//④.排除依赖
implementation(‘org.hibernate:hibernate-core:3.6.3.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’
//⑤.不允许依赖传递
implementation(‘org.hibernate:hibernate-core:3.6.3.Final’){
//不允许依赖传递,一般不用
transitive(false)
}
//⑥.强制使用某个版本,以下两种方式推荐使用第一种
implementation(‘org.slf4j:slf4j-api:1.4.0!!’)
或者
implementation(‘org.slf4j:slf4j-api:1.4.0’){
version{
strictly(“1.4.0”)
}
}
//⑦.设置当依赖冲突,就构建失败。下面我们配置,当 Gradle 构建遇到依赖冲突时,就立即构建失败
configurations.all() {
Configuration configuration ->
//当遇到版本冲突时直接构建失败configuration.resolutionStrategy.failOnVersionConflict()
}
}
还有一种依赖方式是api依赖,需要在build.gradle中声明id 'java-library'
,api 与implementation 区别
总之,除非涉及到多模块依赖,为了避免重复依赖,咱们会使用api,其它情况我们优先选择implementation,拥有大量的api 依赖项会显著增加构建时间。
implementation 类似 maven 中的依赖的dep,对比 maven 中的依赖:
项目实质上是 Task 对象的集合。一个 Task 表示一个逻辑上较为独立的执行过程,比如编译Java 源代码,拷贝文件, 打包Jar 文件,
甚至可以是执行一个系统命令。另外,一个 Task 可以读取和设置Project 的Property 以完成特定的操作
让我们来先看一个例子:
task A {
println “root taskA” //在任务的配置阶段执行
doFirst(){
println “root taskA doFirst”//在任务的执行阶段执行,并且doFirst 在doLast 执行之前执行。
}
doLast(){
println “root taskA doLast”
}
}
gradle中对文件的操作案例:
使用 Project.file(java.lang.Object)方法,通过指定文件的相对路径或绝对路径来对文件的操作,
其中相对路径为相对当前project[根project 或者子project]的目录。其实使用 Project.file(java.lang.Object)方法
创建的 File 对象就是 Java 中的 File 对象,我们可以使用它就像在 Java 中使用一样。示例代码如下:
//使用相对路径
File configFile = file(‘src/conf.xml’)
configFile.createNewFile();
// 使用绝对路径
configFile = file(‘D:\conf.xml’)
println(configFile.createNewFile())
// 使用一个文件对象
configFile = new File(‘src/config.xml’)
println(configFile.exists())
文 件 集 合 就 是 一 组 文 件 的 列 表 , 在 Gradle 中 , 文 件 集 合 用 FileCollection 接 口 表 示 。 我 们 可 以 使 用
Project.files(java.lang.Object[])方法来获得一个文件集合对象,如下代码创建一个 FileCollection 实例:
def collection = files(‘src/test1.txt’,new File(‘src/test2.txt’),[‘src/test3.txt’, ‘src/test4.txt’])
collection.forEach(){
File it -> it.createNewFile() //创建该文件
println it.name //输出文件名
}
Set set1 = collection.files // 把文件集合转换为java中的Set类型
Set set2 = collection as Set
List list = collection as List// 把文件集合转换为java中的List类型
for (item in list) { println item.name
}
def union = collection + files(‘src/test5.txt’) // 添加或者删除一个集合
def minus = collection - files(‘src/test3.txt’) union.forEach(){File it ->
println it.name
}
对于文件集合我们可以遍历它;也可以把它转换成java 类型;同时还能使用+来添加一个集合,或使用-来删除集合。
文件树是有层级结构的文件集合,一个文件树它可以代表一个目录结构或一 ZIP 压缩包中的内容结构。文件树是从文件集合继承过来的,所以文件树具有文件集合所有的功能。我们可以使用 Project.fileTree(java.util.Map)方法来创建文件树对象, 还可以使用过虑条件来包含或排除相关文件。示例代码如下:
tree = fileTree(‘src/main’).include(‘/*.java’)// 第一种方式:使用路径创建文件树对象,同时指定包含的文件
//第二种方式:通过闭包创建文件树:
tree = fileTree(‘src/main’) {
include '/.java’
}
tree = fileTree(dir: ‘src/main’, include: '**/.java’) //第三种方式:通过路径和闭包创建文件树:具名参数给map传值tree = fileTree(dir: ‘src/main’, includes: [‘/*.java’, '/.xml’, '**/.txt’], exclude: ‘/test/’)
tree.each {File file -> // 遍历文件树的所有文件
println file println file.name
}
Subprojects 与 Allprojects
allprojects 是对所有project(包括Root Project+ child Project[当前工程和所有子工程])的进行统一配置,而subprojects
是对所有Child Project 的进行统一配置。
subprojects(){
project(‘subject01’) {
task subject01 {
doLast {
println ‘for subject01’
}
}
}
}
● 我们可以创建多少个 build
● project 和task,他们有什么作用;又是什么关系,如何配置
task是任务执行,任务执行语法:gradle [taskName…] [–option-name…]。
例如:
gradle build: 构建项目:编译、测试、打包等操作
gradle run :运行一个服务,需要application 插件支持,并且指定了主启动类才能运行
gradle clean: 请求当前项目的 build 目录
gradle init : 初始化 gradle 项目使用
gradle wrapper:生成wrapper 文件夹的。
● gradle wrapper 升级wrapper 版本号:gradle wrapper --gradle-version=4.4
● gradle wrapper --gradle-version 5.2.1 --distribution-type all :关联源码用
● 项目的生命周期
案例:计算 Gradle 构建过程中各个阶段的耗时:需要注意,这里只是计算了初始化阶段的 settings 文件,并没有计算init.gradle 初始化的时间。
def projectName=rootProject.getName() //定义项目名
long beginOfSetting = System.currentTimeMillis() //初始化阶段开始时间
def beginOfConfig // 配置阶段开始时间
def configHasBegin = false //配置阶段是否开始了,只执行一次
def beginOfProjectConfig = new HashMap() //存放每个build.gradle 执行之前的时间
def beginOfTaskExecute // 执行阶段开始时间
gradle.projectsLoaded { // 初始化阶段执行完毕
println "${projectName}工程 初始化总耗时 ${System.currentTimeMillis() - beginOfSetting} ms"
}
//build.gradle 执行前
gradle.beforeProject {Project project -> if(!configHasBegin){
configHasBegin = true
beginOfConfig = System.currentTimeMillis()
}
beginOfProjectConfig.put(project,System.currentTimeMillis())
}
//build.gradle 执行后
gradle.afterProject {Project project ->
def begin = beginOfProjectConfig.get(project)
if(project.name == projectName) {
println "根工程${projectName} 配置阶段耗时:${System.currentTimeMillis() - begin} ms"
}else{
println "子工程${project.name} 配置阶段耗时:${System.currentTimeMillis() - begin} ms"
}
}
gradle.taskGraph.whenReady {//配置阶段完毕
println "整个${projectName}项目在配置阶段总耗时:${System.currentTimeMillis() - beginOfConfig} ms"
beginOfTaskExecute = System.currentTimeMillis()
}
//执行阶段开始
gradle.taskGraph.beforeTask {Task task ->
task.doFirst {
task.ext.beginOfTask = System.currentTimeMillis()
}
task.doLast {
println "${task.name}在执行阶段耗时:${System.currentTimeMillis() - task.ext.beginOfTask} ms"
}
}
gradle.buildFinished {//执行阶段完毕
println " 执行阶段总耗时:${System.currentTimeMillis() - beginOfTaskExecute} ms"
println " 整个构建过程耗时:${System.currentTimeMillis() - beginOfSetting} ms"
}
● 项目发布
● 使用Gradle 创建SpringBoot 项目等
4、gradle插件
1、gradle插件文件就是build.gradle
2、脚本插件文件,脚本插件的本质就是一个脚本文件,使用脚本插件时通过apply from:将脚本加载进来就可以了,后面的脚本文件可以是本地的也可以是网络上的脚本文件,下面定义一段脚本,我们在 build.gradle 文件中使用它,具体如下:
- 新建version.gradle文件
//version.gradle文件
ext {
company= "尚硅谷"
cfgs = [compileSdkVersion : JavaVersion.VERSION_1_8]
spring = [version : '5.0.0']
}
- 在build.gradle中引入version.gradle文件
下面将将在构建文件中使用这个脚本文件,具体如下:
//build.gradle文件
//map作为参数
apply from: 'version.gradle'
task taskVersion{
doLast{
println "公司名称为:${company},JDK版本是${cfgs.compileSdkVersion},版本号是${spring.version}"
}
}
上述代码的执行结果如下:
PS D:\repos\idearepos\root> gradle -q taskVersion
版本是2.0,版本号是1
意义:脚本文件模块化的基础,可按功能把我们的脚本进行拆分一个个公用、职责分明的文件,然后在主脚本文件引用, 比如:将很多共有的库版本号一起管理、应用构建版本一起管理等。
补充说明:ext 配置的是用户自定义属性,而gradle.properties 中一般定义 系统属性、环境变量、项目属性、JVM 相关配置信息。
比如下面的gradle.properties 文件案例:加快构建速度的,gradle.properties 文件中的属性会自动在项目运行时加载。
## 设置此参数主要是编译下载包会占用大量的内存,可能会内存溢出
org.gradle.jvmargs=-Xms4096m -Xmx8192m ## 开启gradle缓存
org.gradle.caching=true #开启并行编译org.gradle.parallel=true #启用新的孵化模式
org.gradle.configureondemand=true #开启守护进程org.gradle.daemon=true
详细请参考:https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_configuration_properties
3、对象插件之内部插件[核心插件]
二进制插件[对象插件]就是实现了 org.gradle.api.Plugin 接口的插件,每个 Java Gradle 插件都有一个 plugin id,比如java插件的使用:
可通过如下方式使用一个 Java 插件: apply plugin : ‘java’ //map具名参数方式或者:
//也可以使用闭包作为project.apply方法的一个参数
apply{
plugin 'java'
}
通过上述代码就将 Java 插件应用到我们的项目中了,对于 Gradle 自带的核心插件都有唯一的 plugin id,其中 java 是Java 插件的 plugin id,这个 plugin id 必须是唯一的,可使用应用包名来保证 plugin id 的唯一性。这里的 java 对应的具体类型是 org.gradle.api.plugins.JavaPlugin,所以可以使用如下方式使用 Java 插件:
//使用方式1:Map具名参数,全类名
apply plugin:org.gradle.api.plugins.JavaPlugin
//org.gradle.api.plugins默认导入:使用方式2 apply plugin:JavaPlugin
apply plugin: ‘java’ //核心插件,无需事先引入,使用方式3:插件的id
Gradle 中提供的二进制插件【核心插件】,可参考: https://docs.gradle.org/current/userguide/plugin_reference.html
4、对象插件之第三方插件
- 第三方插件已经被托管在 https://plugins.gradle.org/ 网站上,直接使用新出的 plugins DSL 的方式引用,案例如下: 使 用 plugins DSL 方 式
plugins {
id ‘org.springframework.boot’ version ‘2.4.1’
}
- 如果使用第三方发布的二进制插件,没在官网里就要自己添加buildscript 信息,放在build.gradle 文件的最前面
buildscript {
ext {
springBootVersion = "2.3.3.RELEASE"
}
repositories {
mavenLocal()
maven {
url 'http://maven.aliyun.com/nexus/content/groups/public'
}
jcenter()
}
// 此处先引入插件
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
//再应用插件
apply plugin: 'org.springframework.boot' //社区插件,需要事先引入,不必写版本号
5、自定义插件
interface GreetingPluginExtension { Property<String> getMessage() Property<String> getGreeter()
}
class GreetingPlugin implements Plugin<Project> {
void apply(Project project) {
def extension = project.extensions.create('greeting', GreetingPluginExtension) project.task('hello') {
doLast {
println "${extension.message.get()} from ${extension.greeter.get()}"
}
}
}
}
apply plugin: GreetingPlugin
// Configure the extension using a DSL block greeting {
message = 'Hi'
greeter = 'Gradle'
}
参考地址:https://docs.gradle.org/current/userguide/custom_plugins.html
我们直接执行 hello 任务./gradle hello 即可,这种方式实现的插件我们一般不使用,因为这种方式局限性太强,只能本
Project,而其他的Project 不能使用。
四、Groovy 简介
在某种程度上,Groovy 可以被视为Java 的一种脚本化改良版,Groovy 也是运行在 JVM 上,它可以很好地与 Java 代码及其相关库进行交互操作。它是一种成熟的面向对象编程语言,既可以面向对象编程,又可以用作纯粹的脚本语言。大多数有效的 Java 代码也可以转换为有效的 Groovy 代码,Groovy 和 Java 语言的主要。其特点为:
● 功能强大,例如提供了动态类型转换、闭包和元编程(metaprogramming)支持
● 支持函数式编程,不需要main 函数
● 默认导入常用的包
● 类不支持 default 作用域,且默认作用域为public。
● Groovy 中基本类型也是对象,可以直接调用对象的方法。
● 支持DSL(Domain Specific Languages 领域特定语言)和其它简洁的语法,让代码变得易于阅读和维护。
● Groovy 是基于Java 语言的,所以完全兼容Java 语法,所以对于java 程序员学习成本较低。详细了解请参考:http://www.groovy-lang.org/documentation.html
● 类型转换:当需要时,类型之间会自动发生类型转换: 字符串(String)、基本类型(如int) 和类型的包装类 (如Integer)
● 类说明:如果在一个groovy 文件中没有任何类定义,它将被当做 script 来处理,也就意味着这个文件将被透明的转换为一个 Script 类型的类,这个自动转换得到的类将使用原始的 groovy 文件名作为类的名字。groovy 文件的内容被打包进run 方法,另外在新产生的类中被加入一个main 方法以进行外部执行该脚本。
● 没有可见性修饰符的类或方法自动是公共的(可以使用一个特殊的注释来实现包的私有可见性)。
● 没有可见性修饰符的字段将自动转换为属性,不需要显式的 getter 和 setter 方法。
● 如果属性声明为 final,则不会生成 setter。
● 一个源文件可能包含一个或多个类(但是如果一个文件不包含类定义的代码,则将其视为脚本)。脚本只是具有一些特殊约定的类,它们的名称与源文件相同(所以不要在脚本中包含与脚本源文件名相同的类定义)。