Gradle知识点整理(1)

153 阅读14分钟

常见的项目构建工具

  • Ant:

    • 优点: 使用灵活,速度快(快于 gradle 和 maven)
    • 缺点:Ant没有强加任何编码约定的项目目录结构,开发人员需编写繁杂 XML 文件构建指令,对开发人员是一个挑战
  • Maven

    • 优点: 遵循一套约定大于配置的项目目录结构,使用统一的 GAV 坐标进行依赖管理,侧重于包管理
    • 缺点: 项目构建过程僵化,配置文件编写不够灵活、不方便自定义组件,构建速度慢于 gradle
  • Gradle

    • 优点:集 Ant 脚本的灵活性+Maven 约定大于配置的项目目录优势,支持多种远程仓库和插件,侧重于大项目构建
    • 缺点: 学习成本高、资料少、脚本灵活、版本兼容性差等

Gradle安装

SpringBoot 官方文档明确指出,目前 SpringBoot 的 Gradle 插件需要 gradle6.8 版本及以上,所以我们这里选择 7x 版本

其中SpringBoot与Gradle存在版本兼容问题,Gradle与Idea也存在兼容问题,所以要选择Gradle6.8版本以及高于6.8版本的Gradle

Important Tips:

  • 打开Idea安装目录下的\plugins\gradle\lib,能查看Idea与Gradle相对应的Gradle版本号
  • 选择Spring Boot时一定要注意Spinrg Boot 和JDK 的版本

具体安装步骤参考以下文档:

Gradle和Maven项目结构

修改Maven下载源

我们可以在gradle的init.d目录下创建以.gradle结尾的文件,.gradle文件可以实现在build开始之前执行,所以可以在这个文件配置一些你要预先加载的操作

将以下内容复制到init.d目录下的init.gradle文件中:

  • 项目所需要的架包会前往repositories中区下载
  • 而buildscript是给build.gradle使用的
  • mavenLocal() 即为maven本地仓库
  • mavenCentral() 即为maven重要仓库
 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文件的方法:

  1. 在命令行指定文件,例如:gradle -init-script yourdir/init,gradle -q taskName。你可以多输入此命令来指定多个init文件
  2. 把init.gradle文件放到 USER_HOME/.gradle/ 目录下(即放到C盘下的当前用户目录下的.gradle文件夹下)
  3. 把以.gradle结尾的文件放到 USER_HOME/.gradle/init.d/ 目录下(即放到C盘下的当前用户目录下的.gradle文件夹下的init.d文件夹下)
  4. 把以.gradle结尾的文件放到 GRADLE_HOME/init.d/ 目录下(即gradle安装目录下的init.d文件夹下)

如果以上四种方式,存在两种,那么gradle会按照上面的顺序从1到4依次执行,如果给定目录下存在多个init脚本,会按拼音a-z顺序执行这些脚本,每个init脚本都存在一个对应的gradle实例,你在这个文件中调用的所有方法和属性,都会委托给这个gradle实例,每个init脚本都实现了Script接口。

其他类型的Maven的Aliyun地址

阿里云云效Maven

插件类的仓库地址,最好放到 buildscript

Gradle.properties

 # 开启守护进程,下一次构建的时候,会连接这个守护进程进行构建,而不是重新fork一个进程进行构建
 org.gradle.daemon=true
 # 设置JVM堆内存大小
 org.gradle.jvmargs=-Xmx4096m -XX:MaxPermSize=1024m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
 # 并行编译
 org.gradle.parallel=true
 # 按需加载
 org.gradle.configureondemand=true
 # 开启gradle缓存
 org.gradle.caching=true

Gradle Wrapper

Gradle Wrapper 实际上就是对Gradle的一层包装,用于解决实际开发中可能会遇到的不同项目需要不同版本的Gradle问题,例如:把自己代码共享给别人,发现别人的没有安装Gradle、或者别人的Gradle版本太老旧。

如何使用Gradle Wrapper

Gradle指令和Gradlew指令是不一样的,并且版本也有可能不一样。原因是因为Gradle指令使用的是本地安装的Gradle,Gradlew使用的是Gradle Wrapper中的Gradle,不过最终指令的使用方式是一样的。

对于Gradlew指令时,我们也可以用一些参数来控制Wrapper的生产,比如依赖的版本等:

参数名称参数说明参数示例
--gradle-version用于指定使用的Gradle版本gradle wrapper --gradle-version=7.4.2
--gradle-distribution-url用于指定下载的Gradle发行版的urlgradle wrapper --gradle-version 7.4.2 --distribution-type all

GradleWrapper执行流程

1.当我们第一次执行 ./gradlew build 命令的时候,gradlew 会读取 gradle-wrapper.properties 文件的配置信息

2.准确的将指定版本的 gradle 下载并解压到指定的位置GRADLE_USER HOME目录下的wrapper/dists目录中

3.并构建本地缓存(GRADLE_USER HOME目录下的caches目录中),下载再使用相同版本的gradle就不用下载了

4.之后执行的 ./gradlew 所有命令都是使用指定的 gradle 版本

何时使用Gradle Wrapper

下载别人的项目或者使用操作以前自己写的不同版本的gradle项目时:用Gradle wrapper,也即:gradlew,什么时候使用本地gradle?新建一个项目时:使用gradle指令即可。

Groovy学习

Groovy 是 用于Java虚拟机的一种敏捷的动态语言,它是一种成熟的面向对象编程语言,既可以用于面向对象编程,又可以用作纯粹的脚本语言。使用该种语言不必编写过多的代码,同时又具有闭包和动态语言中的其他特性。

Groovy是JVM的一个替代语言(替代是指可以用 Groovy 在Java平台上进行 Java 编程),使用方式基本与使用 Java代码的方式相同,该语言特别适合与Spring的动态语言支持一起使用,设计时充分考虑了Java集成,这使 Groovy 与 Java 代码的互操作很容易。(注意:不是指Groovy替代java,而是指Groovy和java很好的结合编程。)

Groovy与Java的主要区别

  • 没有可见性修饰符的类或方法自动是公共的(可以使用一个特殊的注释来实现包的私有可见性)
  • 没有可见性修饰符的字段将自动转换为属性,不需要显式的 getter 和 setter 方法
  • 如果属性声明为 fnal,则不会生成 setter
  • 一个源文件可能包含一个或多个类(但是如果一个文件不包含类定义的代码,则将其视为脚本)。脚本只是具有一些特殊约定的类,它们的名称与源文件相同(所以不要在脚本中包含与脚本源文件名相同的类定义)。

安装配置

Groovy下载地址

Groovy概要

类型转换:当需要时,类型之间会自动发生类型转换:字符串(String)、基本类型如 (int)和类型的包装类(如 nteger)

类说明: 如果在一个 groovy 文件中没有任何类定义,它将被当做 script 来处理,也就意味着这个文件将被透明的转换为一个Script 类型的类,这个自动转换得到的类将使用原始的 groovy 文件名作为类的名字。groovy 文件的内容被打包进run 方法,另外在新产生的类中被加入一个 main 方法以进行外部执行该脚本。

Groovy字符串操作

Groovy使用字符串时,单引号、双引号使用起来有不同的效果

  • 单引号:不支持变量引用,不支持换行操作
  • 双引号:支持变量引用,不支持换行操作
  • 单引号模板字符串:不支持变量引用,支持换行操作
  • 双引号模板字符串:支持变量引用,支持换行操作

Groovy三大语句结构

官方文档

Groovy类型以及权限修饰符

  1. 原生数据类型
原生包装
booleanBoolean
charCharacter
shortShort
intInteger
longLong
floatFloat
doubleDouble
  1. 类、内部类、抽象类、接口
  2. 注解
  3. Trait:带有方法实现的接口
  4. 权限修饰符:private、public、protected

Groovy集合操作

Groovy支持List、Map集合操作,并且拓展了Java中的API,具体参考官方文档

Groovy类导入

官方文档

Groovy异常处理

官方文档

Groovy闭包

官方文档

定义:是一个开放的、匿名的代码块,它可以接受参数、也可以有返回值。闭包可以引用其周围作用域中声明的变量。

语法:

 { [closureParameters -> ] statemets }

调用:

  1. 将闭包赋值给一个变量
  2. 变量名()、变量名.call()

示例:

 def running = { who ->
     println("$who start")
 }
 ​
 running("code")
 running().call("code")
 ​
 //____________分割_______________
 def running(Closure closure) {
     println("running start")
     println("running end")
 }
 ​
 running({println("running")})
 ​
 //____________分割_______________
 def caculate(num1,num2,Closure closure){
     closure(num1,num2)
 }
 ​
 caculate(10,15,{k,v -> println("$k + $v = ${k+v}")})
 // 闭包作为方法的最后一个参数,那么闭包可以写在方法外边
 caculate(10,15){k,v -> println("$k + $v = ${k+v}")}
 //____________分割_______________
 def caculate(Closure closure){
     def num1 = 10
     def num2 = 15
     closure(num1,num2)
 }
 ​
 caculate(){k,v -> println("$k + $v = ${k+v}")}
 caculate{k,v -> println("$k + $v = ${k+v}")}

Gretty项目部署

官网地址

Tips:Gradle 6.x版本以前对Gretty支持比较友好

Gretty核心功能:

  • 底层支持jerry,tomcat等Servlet容器
  • 支持热部署、Https、调试

具体使用

  1. 项目引入Gretty
 plugins {
     id 'war'
     id 'org.gretty' version '2.2.0'
 }
  1. 指定maven仓库
 repositories {
     jcenter()
     mavenCentral()
 }
  1. Gretty 插件设置
 gretty {
     httpPort = 8888
     contextPath = "/web"
     debugPort = 5005
     debugSuspend = true
     httpsEnabled = true
     // 热部署
     manageClassReload = true
     // 如果不指定默认容器,则默认使用Jetty
     // servletContainer = 'tomcat'
     httpsPort = 4431
 }
  1. 执行命令:gradle appRun

Gradle项目生命周期

Gradle项目的生命周期分为三大阶段:Initialization -> Configuration -> Execution

Gradle中的setting文件

作用:主要作用是在项目初始化阶段确定要引入那些工程,需要加入到项目构建中,为构建项目工程树做准备。

工程树:Gradle中有工程树的概念,类似于Maven中的Project和Module

内容:里面主要定义了当前Gradle项目以及子Project的项目名称

位置:必须放在根工程下

名字:为setting.gradle文件,不能发生变化

对应实例:与org.gradle.api.initialization.Settings 实例是一一对应的关系。每个项目只有一个settings文件。

关注:只需关注文件中的 include 方法。

一个子工程只有再settings文件中配置了才会被gradle识别,构建时才会被包含

 // 根项目名称
 rootProject.name = 'gradle_tree'
 // 子模块名称
 include 'sub_01'
 include 'sub_02'
 include 'sub_03'
 // 包含的子工程下的子工程名称
 include 'sub_01:subProject01'
 include 'sub_02:subProject02'

Gradle的Task

 tasks.named('test') {
     // 任务配置段,在配置阶段执行
     println "this is task example"
     // 任务的行为:在执行阶段执行
     doFirst {
         println "task first task"
     }
     doLast {
         println "task last task"
     }
 }

运行任务

 gradle -i test

任务的doFirst、doLast都可以在任务的外部定义

 tasks.named('test') {
     // 任务配置段,在配置阶段执行
     println "this is task example"
 }
 ​
 test.doFirst {
     println "task first task"
 }
 test.doLast {
     println "task last task"
 }

底层原理解析:无论是定义任务自身的 action,还是添加的 doLast、doFirst 方法,其实底层都被放入到一个 Action 的 List中了,最初这个action List 是空的,当我们设置了 ation[任务自身的行为],它先将 actin 添加到列表中,此时列表中只有一个action,后续执行doFirst的时候 doFirst在 action 前面添加,执行 doLast 的时候 doLast 在 action 后面添加。doFirst永远添加在 actions List 的第一位,保证添加的 Action 在现有的 action List 元素的最前面;doLast 永远都是在 action List末尾添加,保证其添加的 Action 在现有的 ction List 元素的最后面。一个往前面添加一个往后面添加,最后这个 actionList 就按顺序形成了 doFirst、 doSelf、 doLast 三部分的 Actions,就达到 doFirst、 doSelf、doLast 二部分的 Actions 顺序执行的目的。

Tips:其中<<代表dolast,在Gradle5.x版本之后就废弃了。

任务的依赖方式

  • 参数方式依赖
 taks 'A' {
     doLast {
         println "task A"
     }
 }
 ​
 taks 'B' {
     doLast {
         println "task B"
     }
 }
 ​
 taks 'C'(dependsOn: ['A','B']) {
     doLast {
         println "task C"
     }
 }
  • 内部依赖
 taks 'C' {
     dependsOn = ['A','B']
     doLast {
         println "task C"
     }
 }
 // ==================
 taks 'C' {
     doLast {
         println "task C"
     }
 }
 c.dependsOn = ['A','B']
  • 外部依赖
 // subproject01 工程
 taks 'A' {
     doLast {
         println "task A"
     }
 }
 // subproject02 工程
 taks 'B' {
     dependsOn(":subproject01:A")
     doLast {
         println "task B"
     }
 }

Tips1:当一个Task依赖多个Task的时候,被依赖的Task之间如果没有依赖关系,那么它们的执行顺序是随机的。

Tips2:重复依赖的任务只会执行一次,比如:

任务的执行

官方文档

语法:gradle [taskanme] [--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 projects:列出所选项目及子项目列表,以层次结构的形式显示 
 gradle tasks:列出所选项目[当前 project,不包含父、子]的已分配给任务组的那些任务 
 gradle tasks -all:列出所选项目的所有任务 
 gradle tasks -group="build setup":列出所选项目中指定分组中的任务 
 gradle help -task someTask:显示某个任务的详细信息 
 gradle dependencies:查看整个项目的依赖信息,以依赖树的方式显示 
 gradle properties:列出所选项目的属性列表
 ​
 # 调试选项
 -h,--help:查看帮助信息 
 -v,--version:打]印Gradle、Groovy、 AntJVM 和操作系统版本信息 
 -S,-full-stacktrace:打印出所有异常的完整(非常详细)堆栈跟踪信息 
 -s,-stacktrace:打印出用户异常的堆栈跟踪(例如编译错误)
 -Dorg.gradle,daemon.debug=true:调试 Gradle 守护进程 
 -Dorg.gradle.debug=true:调试 Gradle 客户端(非 daemon)进程 
 -Dorg.gradle.debug.port=(port number):指定启用调试时要侦听的端口号。默认值为 5005
 ​
 # 性能选项
 -build-cache,--no-build-cache:尝试重用先前版本的输出。默认关闭(off)。 
 -max-workers:设置 Gradle 可以使用的 woker数。默认值是处理器数 
 -parallel,-no-parallel:并行执行项目。有关此选项的限制,请参阅并行项目执行默认设置为关闭(off)
 ​
 # 守护进程
 -daemon,--no-daemon:使用守护进程运行构建。默认是 onGradle 
 -foreground:在前台进程中启动 Gradle 守护进程 
 -Dorg.gradle.daemon.idletimeout=(number of milliseconds):Gradle Daemon 将在这个空闲时间的毫秒数之后停止自己。默认值为 1000000(3 小时)
 ​
 # 日志选项
 -Dorg.gradle.logging.level=(quiet,warn,lifecycle,info,debug):通过 Gradle 属性设置日志记录级别。 
 -q,-quiet:只能记录错误信息 
 -w,--warn:设置日志级别为 warn 
 -i,--info:将日志级别设置为 info 
 -d,-debug:登录调试模式(包括正常的堆栈跟踪)
 ​
 # 其他
 -x:-x 等价于:-exclude-task:常见 gradle -x test clean build 
 -rerun-tasks:强制执行任务,忽略up-to-date ,常见 gradle build -rerun-tasks 
 -continue:忽略前面失败的任务.继续执行,而不是在遇到第一个失败时立即停止执行。每个遇到的故障都将在构建结束时报告,常见: gradle build -continue。 
 gradle init -type pom:将 maven 项目转换为 gradle 项目(根目录执行) 
 gradle [taskName]:执行自定义任务

Gradle默认各指令之间相互的依赖关系

任务的定义方式

任务定义方式,总体分为两大类,一种是通过Project中的task方法,另一种是通过tasks对象的create或者register方法。

 task('A',{ // 任务名称,闭包都作为参数
     println "task a"
 })
 ​
 task('B'){ // 闭包作为最后一个参数可以直接从中括号中拿出来
     println "task b"
 }
 ​
 task C { // groovy语法支持省略方法括号
     println "taks c"
 }
 // 以上三种方法本质上是一种方法
 ​
 def map = new HashMap<String,Object>();
 map.put("aciton",{println "task d"})// action属性可以设置为闭包
 taks(map,"D");
 ​
 task.create("E"){ // 使用 task 的create方法
     println "task e"
 }
 ​
 task.register("F"){ // register执行是延迟创建,即只有当task被需要的时候才会创建
     println "task f"
 }

任务的属性

配置项描述默认值
type基于一个存在的task来创建,和java中的类继承相似DefaultTask
overwrite是否替换一个存在的task,这个和type配合使用false
dependsOn用于配置任务的依赖[]
action添加到任务中的一个Action或者一个闭包null
description任务的描述null
group任务的分组null
 // 1.F是任务名,以参数的方式指定任务的属性信息
 task(grou: "alan", description: "this is task F","F")
 ​
 // 2.H是任务名,任务定义的同时,直接在内部指定属性信息
 task("H"){
     group("alan")
     description("this is task H")
 }
 ​
 // 3.Y是任务名,给已有的任务 在外部指定属性信息
 task("Y"){}
 y.group = "alan"
 y.description = "this is task Y"