当前位置: 首页 > news >正文

Gradle学习笔记

写在前面

Gradle是一个开源的构建自动化工具,足够灵活,可以构建几乎任何类型的软件。Gradle对你要构建什么或如何构建它几乎没有任何假设。这使得Gradle特别灵活。

安装

官网下载

Gradle Wrapper

gradle wrapper的优点之一就是可以自定义下载的gradle的版本,如果是团队协作的话,这个功能就非常方便,简单设置即可统一团队的构建工具版本。

gradle-wrapper.properties文件内容

distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
  • distributionBase: Gradle 解包后存储的父目录;
  • distributionPath:distributionBase指定目录的子目录。distributionBase+distributionPath就是 Gradle 解包后的存放的具体目录;
  • distributionUrl: Gradle 指定版本的压缩包下载地址;
  • zipStoreBase: Gradle 压缩包下载后存储父目录;
  • zipStorePath:zipStoreBase指定目录的子目录。zipStoreBase+zipStorePath就是 Gradle 压缩包的存放位置。

基本概念

项目

项目(Projects)是gradle构建的东西,项目会包含一个构建脚本,一般在项目根目录下,叫做build.gradle或者build.gradle.kts。构建脚本为项目定义任务、依赖项、插件和其他配置。单次构建可以包含一个或多个项目,每个项目可以包含子项目。

每一个构建都是由一个或多个 projects 构成的。一个 project 到底代表什么依赖于你想用 Gradle 做什么。举个例子,一个 project 可以代表一个 JAR 或者一个网页应用。它也可能代表一个发布的 ZIP 压缩包,这个 ZIP 可能是由许多其他项目的 JARs 构成的。但是一个 project 不一定非要代表被构建的某个东西。它可以代表一件**要做的事,比如部署你的应用.

任务

任务(Tasks)包含执行某些工作的逻辑,比如编译代码、运行测试或部署软件。在大多数用例中,您将使用现有已存在的任务。Gradle提供了一些实现了许多常见构建系统需求的任务,例如可以运行测试的内置Java Test 任务。插件提供更多类型的任务。

任务的组成:

  • 操作(Actions):执行某些操作的工作片段,如复制文件或编译源代码
  • 输入(Inputs):Actions使用或操作的值、文件和目录
  • 输出(Outputs):Actions修改或生成的文件和目录

每一个 project 是由一个或多个 tasks 构成的. 一个 task 代表一些更加细化的构建. 可能是编译一些 classes, 创建一个 JAR, 生成 javadoc, 或者生成某个目录的压缩文件.

插件

插件允许您在构建中引入新的概念,而不仅仅是任务、文件和依赖项配置。例如,大多数语言插件都将源集的概念添加到构建中。

插件提供了一种跨多个项目重用逻辑和配置的方法。使用插件,您可以编写一次任务并在多个构建中使用它。或者,您可以在一个地方存储常见配置,如日志记录、依赖项和版本管理。这减少了构建脚本中的重复。使用插件对构建过程进行适当的建模可以极大地提高易用性和效率。

构建生命周期

Gradle在构建生命周期的三个构建阶段评估和执行构建脚本:

  • 初始化阶段:设置生成的环境并确定哪些项目将参与其中。
  • 配置阶段:构造并配置生成的任务图。根据用户要运行的任务确定需要运行哪些任务以及运行顺序。
  • 执行阶段:运行在配置阶段结束时选择的任务。

构建

构建(Build)是Gradle项目中任务集合的执行。您可以通过命令行界面(CLI)或IDE指定任务选择器来运行生成。Gradle配置构建并选择要运行的任务。Gradle基于请求的任务及其依赖关系运行最小的完整任务集。

项目结构

  • gradle:gradle-wrapper存放位置
  • src:与maven目录一致
  • build.gradle:gradle项目构建文件
  • gradlew:gradle命令行工具
  • settings.gradle:多模块项目配置文件

命令

-q

比如以下命令

gradle -q hello

-q 代表 quite 模式. 它不会生成 Gradle 的日志信息 (log messages), 所以用户只能看到 tasks 的输出. 它使得的输出更加清晰. 你并不一定需要加入这个选项.

列出项目所有任务

gradle tasks

列出项目的所有属性

gradle properties

注意

<<

task hello << {println 'Hello world!'
}

这个代码会报错,因为在build.gradle脚本中的"<<"符号已经被弃用。

解决方法是使用doLast

task hello {doLast {println 'Hello world!'}
}

项目API

project

简介

对于构建脚本中每个项目,Gradle 都创建了一个 Project 类型的对象用来关联此项目. 当构建脚本执行时,它会去配置所关联的 Project 对象.

  • 构建脚本中每个被调用的方法(这些方法并未在构建脚本中定义)都被委托给当前 Project 对象(使用 Project 对象引用方法)。

  • 构建脚本中每个被操作的属性(这些属性并未在构建脚本中定义)都被委托给当前 Project 对象(使用 Project 对象引用属性).

比如说以下build.gradle脚本

println name
println project.name

使用 gradle -q check 命令输出结果:

> gradle -q check
projectApi
projectApi

第一个输出使用的是自动委托 ( auto-delegation ),因为当前属性并没有在构建脚本中定义.

第二个语句使用了项目一个属性,这个属性在任何构建脚本中都可用,它的返回值是被关联的 Peoject 对象的目录名。

标准项目属性

以下是常见属性

NameTypeDefault Value
projectProjectProject 实例对象
nameString项目目录的名称
pathString项目的绝对路径
descriptionString项目描述
projectDirFile包含构建脚本的目录
buildFileprojectDir/build
groupObject未具体说明
versionObject未具体说明
antAntBuilderAnt实例对象

注意,我们的构建脚本只是个很简单的 Groovy 代码 ,不过它会再调用 Gradle API,Project 接口通过调用 Gradle API 让我们可以操作任何事情

脚本 API

简介

当 Gradle 执行一个脚本时,它会将这个脚本编译为实现了 Script 的类. 也就是说所有的属性和方法都是在 Script 接口中声明的,由于你的脚本实现了 Script 接口,所以你可以在自己的脚本中使用它们.

变量

在 Gradle 构建脚本中有两种类型的变量可以声明:局部变量 ( local ) 和 扩展属性 ( extra ) .

局部变量

局部变量使用关键字 def 来声明,其只在声明它的地方可见 . 局部变量是 Groovy 语言的一个基本特性.

build.gradle

def dest = "dest"task copy(type: Copy) {form "source"into dest
}

扩展属性

在 Gradle 领域模型中所有被增强的对象能够拥有自己定义的属性. 这包括,但不仅限于 projects , tasks , 还有 source sets . Project 对象可以添加,读取,更改扩展的属性. 另外,使用 ext 扩展块可以一次添加多个属性.

build.gradle

apply plugin: "java"// 一个 ext 扩展块向 Project 对象添加了两个扩展属性. 
ext {springVersion = "3.1.0.RELEASE"emailNotification = "build@master.org"
}// 名为 purpose 的属性被添加到每个 source set,然后设置 ext.purpose 等于 null ( null值是被允许的 ). 当这些扩展属性被添加后,它们就像预定义的属性一样可以被读取,更改值.
sourceSets.all { ext.purpose = null }sourceSets {main {purpose = "production"}test {purpose = "test"}plugin {purpose = "production"}}task printProperties << {println springVersionprintln emailNotificationsourceSets.matching { it.purpose == "production" }.each { println it.name }}
}

插件

在Gradle中一般有两种类型的插件,脚本插件和二进制插件.脚本插件是额外的构建脚本,它会进一步配置构建,通常实行声明的方式操纵的构建.尽管他们可以外部化并且从远程位置访问,它们通常还是会在构建内部中使用.二进制插件是实现了Plugin接口的类,并且采用编程的方式来操纵构建.二进制插件可以驻留在构建脚本,项目层级内或外部的插件jar.

脚本插件

build.gradle

apply from: 'other.gradle'

脚本插件可以从本地文件系统或在远程位置的脚本中应用.文件系统的位置是相对于项目目录,而远程脚本位置的是由一个HTTP URL指定的.多个脚本插件(两种形式之一)可以被应用到给定的构建。

二进制插件

build.gradle

apply plugin: 'java'

插件可以使用插件ID应用.插件的id作为给定的插件的唯一标识符.核心插件注册一个可以用作插件的id的短名称.在上述情况下,我们可以使用简称java的插件以应用JavaPlugin.

插件DSL

build.gradle

plugins {id 'java'
}

要从插件门户应用一个社区插件,必须使用插件的完全限定id

新插件{}块不支持任意Groovy代码.被限制的原因是为幂等(每次产生相同的结果)和无副作用(为了Gradle随时执行的安全).

形式是:

plugins{id «plugin id»  version «plugin version»
}

«plugin id»«plugin version»必须是常量,字面量,字符串.其他语句都是不允许的;他们的存在会导致编译错误.

插件{}块也必须在构建脚本的顶部声明.它不能被嵌套在另一个结构(例如,if语句或for循环).

插件{}块目前只能在一个项目的构建脚本中使用.他不能在脚本插件,settings.gradle和出书画脚本中使用.

不能与subjects{},allprojects{}等结合使用,每个项目都必须在自己的构建脚本中的plugins{}块中声明应用的插件.

Java插件

Java 插件引入了许多任务到项目当中

java plugin-tasks

依赖项

api

api关键字表示该依赖项将会被暴露给模块的公共接口。如果一个模块依赖于另一个模块,并且在其公共接口中使用了该依赖项,那么该依赖项应该使用api关键字声明。这意味着,如果一个模块依赖于该模块,并且使用了该依赖项,那么它也会自动依赖于该依赖项。

implementation

implementation关键字表示该依赖项仅在模块的内部使用,并不会暴露给其他模块。如果一个模块依赖于另一个模块,但不会在其公共接口中使用该依赖项,那么该依赖项应该使用implementation关键字声明。这意味着,其他模块依赖于该模块时,不会自动依赖于该依赖项。

api与implementation区别

以下列模块A的配置为例,模块A依赖support模块和support2模块。

dependencies {api(project(":support"))implementation(project(":support2"))
}

如果模块B依赖模块A,那么模块B则会同时依赖support模块,但不会依赖support2模块。support2模块只在A模块内部使用,并不会传递给其他模块。

dependencies {implementation(project(":A"))
}

实践

Gradle使用约定优先于配置的方法来构建基于JVM的项目,该方法借鉴了Apache Maven的几个约定。特别是,它对源文件和资源使用相同的默认目录结构,并且与Maven兼容的存储库一起工作。

创建普通Java项目

参考

  • https://docs.gradle.org/current/samples/sample_building_java_applications.html

1.创建项目文件夹

在目标目录创建一个空文件夹,比如叫做vertx4study

2.执行初始化任务

进入vertx4study文件夹,执行以下命令

gradle init

可能会出现以下界面

$ gradle initSelect type of project to generate:1: basic2: application3: library4: Gradle plugin
Enter selection (default: basic) [1..4] 2Select implementation language:1: C++2: Groovy3: Java4: Kotlin5: Scala6: Swift
Enter selection (default: Java) [1..6] 3Select build script DSL:1: Groovy2: Kotlin
Enter selection (default: Groovy) [1..2] 1Select test framework:1: JUnit 42: TestNG3: Spock4: JUnit Jupiter
Enter selection (default: JUnit 4) [1..4] 4Project name (default: demo): vertx4study
Source package (default: demo): org.example.vertx4studyBUILD SUCCESSFUL
2 actionable tasks: 2 executed

生成的项目目录如下

image-20230531172701456

3.运行应用

在项目根目录下打开CMD执行命令

gradlew run

运行结果

image-20230531173000655

创建多模块Java项目

参考

  • https://docs.gradle.org/current/samples/sample_building_java_applications_multi_project.html

1.创建项目文件夹

在目标目录创建一个空文件夹,比如叫做vertx4study

2.执行初始化任务

进入vertx4study文件夹,执行以下命令

gradle init

可能会出现以下界面

D:\project\java\vertx4study>gradle init
Starting a Gradle Daemon, 1 incompatible and 1 stopped Daemons could not be reused, use --status for detailsSelect type of project to generate:1: basic2: application3: library4: Gradle plugin
Enter selection (default: basic) [1..4] 2Select implementation language:1: C++2: Groovy3: Java4: Kotlin5: Scala6: Swift
Generate multiple subprojects for application? (default: no) [yes, no] yesSelect build script DSL:1: Groovy2: Kotlin
Enter selection (default: Groovy) [1..2] 2Project name (default: vertx4study): vertx4study
Source package (default: vertx4study): org.example.vertx4study
Enter target version of Java (min. 7) (default: 11): 11
Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no]> Task :init
Get more help with your project: https://docs.gradle.org/8.1.1/samples/sample_building_java_applications_multi_project.htmlBUILD SUCCESSFUL in 1m 25s
2 actionable tasks: 2 executed

生成的项目目录如下

image-20230601101248496

3.运行应用

在项目根目录下打开CMD执行命令

gradlew run

运行结果

image-20230601101426476

4.项目结构说明

settings.gradle.kts

D:\project\java\vertx4study\settings.gradle.kts

plugins {// Apply the foojay-resolver plugin to allow automatic download of JDKsid("org.gradle.toolchains.foojay-resolver-convention") version "0.4.0"
}rootProject.name = "vertx4study"
include("app", "list", "utilities")

定义了项目包含三个子项目

  • app
  • list
  • utilities
buildSrc

D:\project\java\vertx4study\buildSrc

buildSrc文件夹中定义了约定插件,使得子项目之间可以重用共享构建逻辑和配置。

buildSrc下的java-common-conventions.gradle.kts

D:\project\java\vertx4study\buildSrc\src\main\kotlin\org.example.vertx4study.java-common-conventions.gradle.kts

java-common-conventions定义了一些配置,这些配置应该由我们所有的Java项目共享,而与它们是表示一个库还是实际的应用程序无关。

首先,我们应用Java插件来获得构建Java项目的所有功能。

plugins {java 
}

然后,我们声明一个repositories库作为外部依赖的源

repositories {mavenCentral() 
}

定义依赖约束以及所有子项目共享的标准依赖,并将JUnit 5设置为测试框架其他共享设置,如编译器标志或JVM版本兼容性,也可以在这里设置。

类似maven的父项目的pom.xml定义的dependencyManagement标签,子项目中的dependencies标签下的依赖就不需要定义版本了。

dependencies {constraints {implementation("org.apache.commons:commons-text:1.10.0") }testImplementation("org.junit.jupiter:junit-jupiter:5.9.1") 
}tasks.named<Test>("test") {useJUnitPlatform() 
}
app/build.gradle.kts

D:\project\java\vertx4study\app\build.gradle.kts

plugins {id("org.example.vertx4study.java-application-conventions")
}dependencies {implementation("org.apache.commons:commons-text")implementation(project(":utilities"))
}application {// Define the main class for the application.mainClass.set("org.example.vertx4study.app.App")
}

app子项目的构建脚本中指定了项目插件、依赖和主类。

问题

找不到插件

比如执行 gradle build 的时候出现以下异常

org.gradle.api.plugins.UnknownPluginException: Plugin [id: 'org.gradle.kotlin.kotlin-dsl', version: '4.0.7'] was not found in any of the following sources:

可以尝试使用

gradle build --rerun-tasks

这样就不会使用缓存了。

IDEA控制台中文乱码

1.检查settings的设置

image-20230601172158518

2.Help→Etit Custom VM Options

增加配置,然后重启IDEA。

-Dfile.encoding=UTF-8

3.在build.gradle(.kts)里设置编码

subprojects {tasks.withType(JavaCompile::class.java) {options.encoding = "UTF-8"}
}

4.打开 IntelliJ IDEA 在本地的安装目录,打开idea64.exe.vmoptions,在最后一行添加

-Dfile.encoding=UTF-8

The end.

相关文章:

  • 内存分页法
  • Windows实时拓展架构-鸿道Intewell-win构型
  • Windows Ubuntu 目录映射关系
  • 在Windows系统中使用C++与Orthanc交互:基于DICOMweb的医学影像应用开发
  • Cribl 中 Parser 扮演着重要的角色 + 例子
  • 【Auto-dl ssh隧道,TensorBoard】
  • FreeRTOS学习笔记【11】-----任务列表
  • 打卡day31
  • 计算机网络基础概念
  • Gas优化利器:Merkle 树如何助力链上数据效率革命
  • ubuntu下docker安装mongodb-支持单副本集
  • 磁盘空间不足,迁移Docker 数据目录
  • 基于自然语言转SQL的BI准确率如何?
  • 《算法笔记》11.8小节——动态规划专题->总结 问题 D: Coincidence
  • linux下jenkins部署安装使用
  • 【图像大模型】Stable Video Diffusion:基于时空扩散模型的视频生成技术深度解析
  • 【HTML-2】HTML 标题标签:构建网页结构的基础
  • 设计模式之备忘录模式
  • 如何使用通义灵码玩转Python - AI编程助手提升效率
  • windows安装WS,实测可行
  • 百年前淮北乡村的风俗画卷——读郑重 《九十自述》
  • 竞彩湃|水晶宫夺冠后乘胜追击,四大皆空曼城人间清醒?
  • 国家发改委:内卷式竞争扭曲市场机制、扰乱公平竞争秩序,必须整治
  • 中国首次当选联合国教科文组织1970年《公约》缔约国大会主席国
  • 花旗回应减员传闻:持续评估人力资源战略,将为受影响的个人提供支持
  • 确诊前列腺癌后,拜登首次发声