目录💻
一、介绍
在java的项目开发过程中我们会使用到一些依赖管理的构建工具、目前常用的主要有Maven和Gradle两种;Maven不用多说,基本上学java的基本上都会用到,毕竟是现在使用最多的,也是使用的比较久的了,但maven由于使用的是XML进行配置,相对比较繁琐,可读性也比较差;而且构建的数据较慢,不支持增量构建;小项目还好,当比较大型的项目时,就会比较影响。所以Apache重新孵化出了一个新的项目,就是Gradle。
Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化构建工具。它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置,而不是传统的XML。Gradle构建脚本是用Groovy编写的,也可以使用Kotlin编写,两者都是基于JVM的语言。
- 老的Gradle项目可能会使用到Groovy编写,但目前spring官方比较推荐的Kotlin编写进行编写;
- Gradle是JVM平台最受欢迎的构建系统,也是Android和Kotlin多平台项目的默认选择,它拥有丰富的社区插件生态系统。
- Gradle可以使用其内置函数、第三方插件或自定义构建逻辑自动执行各种软件构建场景。
- Gradle提供了一种高级、声明式和富有表现力的构建语言,使阅读和编写构建逻辑变得很轻松。
Gradle除了支持Java之外还支持Android、Kotlin Multiplatform、Groovy、Scala、Javascript和C/C++等热门语言的构建工作:
所有常见的IDE都支持Gradle,包括Android Studio、IntelliJ IDEA、Visual Studio Code、Eclipse和NetBeans。
二、安装Gradle
1、下载安装
在使用之前首先得先进行安装,安装可以直接通过官网:https://gradle.org/releases/进行安装,再安装的时候,我们需要查看自己的idea版本对应的Gradle版本,因为Gradle不同版本之间的差距会比较大
- 通过到idea安装路径下的
***\IntelliJ IDEA 2023.2.3\plugins\gradle\lib
查看
我这里使用的是idea2023的版本,对应的是Gradle8.4的版本
通过官方网站点击binary-only进行下载
2、配置环境变量
2.1、mac
安装好后配置环境变量
-
使用文本编辑器(如vim、nano等)打开~/.bash_profile文件。可以使用以下命令:
nano ~/.bash_profile
-
在打开的文件中,添加以下内容:
powershell
# 请将/path/to/your/gradle替换为实际的Gradle安装路径。
export GRADLE_HOME=/path/to/your/gradle
export PATH=$GRADLE_HOME/bin:$PATH
-
:wq
保存文件并关闭文本编辑器。 -
source ~/.bash_profile
认环境变量生效 -
gradle -v
执行查看是否有(如果可以看到版本下面的可以省略) -
如果还是不行,可以配置
~/.zshrc
文件配置//路径需要改为自己的
export PATH=$PATH:/path/to/your/gradle/bin
-
然后执行、在查看版本
source ~/.zshrc
2.2、windows
-
首先负责解压后的安装目录
-
接着我们需要配置相应的环境变量才能使用,打开环境变量配置面板:
-
添加环境变量
GRADLE_HOME
(只能是这个),变量值为刚刚存放的Gradle文件夹位置。接着我们在Path环境变量中添加对应的bin目录:
-
添加完成后,我们打开一个新的命令窗口,输入gradle -v命令查看是否配置生效:
3、配置国内国内镜像源
需要修改一下全局的maven仓库镜像为国内的,要不然下载会非常慢。
到安装路径的**/gradle-8.4/init.d
路径下创建一个 init.gradle
文件,把下面的复制过去。
kotlin
allprojects {
repositories {
def ALIYUN_REPOSITORY_URL = 'https://maven.aliyun.com/repository/public'
def ALIYUN_JCENTER_URL = 'https://maven.aliyun.com/repository/jcenter'
maven {
url ALIYUN_REPOSITORY_URL
name 'Aliyun Public Repository'
}
jcenter {
url ALIYUN_JCENTER_URL
name 'Aliyun JCenter'
}
}
}
4、初始化Gradle项目
完成安装之后,我们可以尝试创建一个gradle项目,主要分为几种方式、可以在spring官网创建;也可以通过命令行创建;但一般我们最常用的肯定是直接通过idea进行创建。
这里掩饰idea进行创建,其他的方式可以百度查看。
-
打开idea进入创建页面,直接创建spring项目,选择Type选择Kotiln,在一些老的教程可能会叫创建Groovy,但目前新的以及官方都是推荐Kotiln,然后选择对应的jdk
注意: 不同版本的Gradle对我们使用的IDEA版本同样存在兼容性问题,这里推荐使用IntelliJ IDEA 2023.3或更高版本,旧版本的IDEA可能会不支持当前的Gradle 8.4版本。
-
添加依赖,这里就添加了两个依赖做测试
-
加载项目
Gradle不好的一点是的跨版本兼容性很差,所以每次创建时会重新下载一次,因此它指定了当前项目中使用的Gradle版本,使得不同的开发人员或CI/CD系统都能使用相同的Gradle版本来构建项目,从而提高项目的一致性和可移植性。当然好处是,它可以自动下载和使用正确版本的Gradle,无需手动安装或配置Gradle,使得项目的维护和协作更加方便,后续别人拿到我们这个项目的时候,不需要自己在系统中部署Gradle环境。
这个过程中可能会很卡,因为服务器在国外(建议挂梯)直到出现BUILD SUCCESSFUL
之后,表示初始化完成:
4.1、项目结构
内容作用:
.gradle
:Gradle自动生成的项目缓存目录。.idea
:这个是IDEA的项目配置目录,跟Gradle生成的没关系,无视掉就行。gradle
:包含JAR文件和Gradle Wrapper的配置。
gradle-wrapper.properties
:编写gradle配置的文件。默认有指定gradle版本等信息src
:存放整个项目的源代码、测试等,这里面就是我们写代码的地方了。
main
:编写所有项目核心代码。test
:编写项目测试代码。build.gradle.kts
:项目的gradle构建脚本。gradlew
:适用于macOS和Linux的使用Gradle Wrapper执行构建的脚本(这里的版本就是GradleWrapper指定的版本)gradlew.bat
:适用于Windows的使用Gradle Wrapper执行构建的脚本。settings.gradle.kts
:定义子项目列表的项目配置文件,也是最关键的设置文件。
其他的没啥作用,不需要管。
4.2、Gradle常用命令
这里我们使用GradleWapper提供的gradlew进行操作,使用方式其实和gradle命令是一样的,只是这里用的是生成的(注意Windows平台下需要使用gradlew.bat来运行)
-
./gradlew.bat task
:windows -
./gradlew task
:查看一下所有Gradle支持的任务(mac/linux) -
./gradlew run
:将当前项目以JVM应用程序的形式运行,这个命令会自动编译并运行我们的项目 -
./gradlew clean
:可以拆分执行,比如先执行清除命令,和maven一样的 -
./gradlew classes
:编译成class文件 -
./gradlew classes -q
: #安静模式,只执行,不打印日志 -
./gradlew build
:快速执行一个完整的编译+测试流程来构建整个项目,并得到打包好的jar等文件 -
./gradlew build -x test
:过滤执行测试
如果觉得敲命令太累了,idea已经自动帮我们集成Gradle插件了,外层的包是分类,内层的对应的每一个命令,也可以自定义插件命令
三、项目配置
项目构建流程
1、配置文件介绍
1.1、设置文件settings.gradle
设置文件settings.gradle
是整个Gradle项目的入口点
对于多项目来说,也是主配置文件,因为Gradle支持单项目和多项目的构建:
- 对于单个项目构建,设置文件是可选的。
- 对于多项目构建,设置文件必须存在,并在其中定义所有子项目。
settings.gradle.kts
和build.gradle.kts
文件一样,也是也是使用Kotlin语言进行编写。如果Groovy生成的就会创建一个settings.gradle
文件,就是使用Groovy语言编写
kotlin
rootProject.name = "gradle-test" //当前项目的名称
include("common") //子项目名称
include("order")
1.1.1、单体项目
1.1.2、父子项目
一个项目的settings.gradle.kts
文件只能有一个,build.gradle.kts
可以每个子项目都有一个
1.2、构建文件gradle.build
但我们是Kotlin
语言构建的gradle.build.kts
文件
生成的格式如下:
kotlin
plugins {
java
id("org.springframework.boot") version "3.2.1"
id("io.spring.dependency-management") version "1.1.4"
}
group = "org.example"
version = "0.0.1-SNAPSHOT"
java {
sourceCompatibility = JavaVersion.VERSION_17
}
configurations {
compileOnly {
extendsFrom(configurations.annotationProcessor.get())
}
}
repositories {
// mavenCentral()
maven{
setUrl("https://maven.aliyun.com/repository/public/")
}
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
compileOnly("org.projectlombok:lombok")
annotationProcessor("org.projectlombok:lombok")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
tasks.withType<Test> {
useJUnitPlatform()
}
在这个配置文件中,基本上是采用lambda语句编写的,对比起maven看起来会更加的简洁美观。所以说虽然Gradle依赖于JVM平台,但是仅支持Kotlin和Groovy,它们相比Java在语法上存在更大的优势,更适合编写这种类似脚本一样的配置文件。
下面来拆分介绍每一块
plugins
函数:用作指定使用哪些插件
kotlin
plugins {
java //一些内部的可以简写,表示使用java语言,相当于:id("java")
id("org.springframework.boot") version "3.2.1" //springboot,version函数用作指定的插件版本
id("io.spring.dependency-management") version "1.1.4" //用作指定spring所管理的依赖的版本,spring有的依赖,就不需要自己去指定版本了,通过该插件统一配置
}
这里的group和version分别设置了当前项目所属的组名称和版本:
kotlin
group = "org.example"
version = "0.0.1-SNAPSHOT"
表示指定的jdk版本
kotlin
java {
sourceCompatibility = JavaVersion.VERSION_17
}
configurations
用作定义项目中使用的不同配置
kotlin
configurations {
compileOnly { //注解处理相关配置,用于Lombok
extendsFrom(configurations.annotationProcessor.get())
}
}
repositories
用于指定仓库,
kotlin
repositories {
// mavenCentral() //指定maven官方仓库
maven{
setUrl("https://maven.aliyun.com/repository/public/") //指定阿里镜像仓库
}
}
- 引入依赖
- 同时引入两个相同的依赖时,默认引入最新版本的
kotlin
dependencies{
implementation("org.springframework.boot:spring-boot-starter-actuator") //引用依赖
implementation(files("C:\\pangea\\messageClient\\1.3.5\\messageClient-1.3.5.jar")) //引入本地指定路径的依赖
implementation(filesTree("pangea")) //引入项目跟路径下的pangea包下的全部jar包依赖
implementation("io.springfox:springfox-swagger-ui:2.9.2"){
exclude("org.springframework") //排除指定依赖
}
implementation("org.springframework:spring-aop:6.1.1!!") //添加双感叹号,表示多个版本时,使用该版本
testImplementation("org.springframework.boot:spring-boot-starter-test") //仅在测试时导入
}
DependencyHandlerScope使用方法,也就是dependencies
,因为dependencies内部引用的是使用的Kotlin语言编写的。
implementation
: 用于添加项目的依赖项,这是最常用的方法。api
: 与 implementation 类似,但它会暴露依赖项给项目的所有模块(多项目配置中讲解)compileOnly
: 用于指定编译时依赖,但不会在运行时包含在最终构建结果中。testImplementation
: 用于添加测试时需要的依赖项。androidTestImplementation
: 用于添加Android测试时需要的依赖项。kapt
: 用于添加 Kotlin 注解处理器依赖项。annotationProcessor
: 用于添加 Java 注解处理器依赖项。runtimeOnly
:仅在运行时使用,不用于编译
1.3、自定义任务
java
tasks.register("myTask"){ //第一个参数为任务名称,第二个参数使用Lambda编写任务具体操作
doFirst{ //使用doFirst向任务队列首部插入新的Action,也就是要执行的内容
println("自定义任务----插入都任务首位")
println("addd")
}
doLast{ //向队列尾部插入Action
println("插入到任务尾部")
}
}
添加后,点击刷新后就会出现对应的任务名称,点击可以执行
- 通过命令行执行:输入对应的任务名称即可
1.4、生命周期钩子
有些时候我们希望在Gradle的整个生命周期中的不同时段执行一些操作,我们可以使用官方提供的生命周期钩子函数。
-
构建初始阶段
gradle.settingsEvaluated()
完成项目的配置阶段之后调用(只能定义在 setting.gradle 或 init.gradle 脚本中)gradle.projectsLoaded()
所有项目加载之后调用(只能定义在 setting.gradle 或 init.gradle 脚本中)
-
配置阶段
gradle.beforeProject()
每个项目完成配置之前调用(只能定义在 setting.gradle 或 init.gradle 脚本中)gradle.afterProject()
每个项目完成配置之后调用gradle.projectEvaluated()
所有项目全部完成配置之后调用gradle.afterEvaluate()
整个配置阶段完成后调用gradle.taskGraph.whenReady
全部任务图已经构建完成可以就绪后调用
-
执行阶段
gradle.taskGraph.beforeTask
执行每一个任务之前调用gradle.taskGraph.afterTask
每一个任务执行完成之后调用gradle.buildFinished
整个构建全部结束后调用
这里我们可以尝试编写一个钩子函数试试看:
kotlin
var time: Long = 0
gradle.settingsEvaluated { //开始任务
println("开始构建")
time = System.currentTimeMillis()
}
gradle.taskGraph.afterTask {//结束任务
val takeTime = System.currentTimeMillis() - time
println("任务: $name 执行耗时: ${takeTime}ms")
println("构建结束")
}
1.5、JVM语言混合编程
如果需要多种语言混合编程
kotlin
plugins {
java
kotlin("jvm") version "1.8.22" //Kotlin/JVM插件
id("application") //打包为可执行的应用,也可以直接使用application插件
}
-
先创建一个存放kotlin可执行文件的目录,和java同层
-
然后再编写kotlin可执行文件
Student.kt
,以kt结尾
-
编写kolin代码,创建一个实体,比Java要简单
kotlin
package com.test
data class Student(val name: String, val age: Int)
- 再通过测试类去调用
java
@SpringBootTest
class GradleSpringTestApplicationTests {
@Test
void contextLoads() {
Student student = new Student("小明", 19);
System.out.println(student);
}
}
输出
1.6、依赖的传递
我们在使用多模块时可能会遇到这样的一个问题,现在有三个模块,并且具有以下依赖关联:
service-a
service-b implementation(service-a)
service-c implementation(service-b)
此时,从链式的依赖关系上来看,它们长这样:service-a -> service-b -> service-c
按照正常的传递关系来说,在B中应该是可以直接使用A中定义的内容的,因为依赖了A模块,同时,由于C依赖了B模块,那么理所应当,C也应该可以直接使用A中定义的内容,我们来看看是否真的如此:
java
//A模块中定义
public class Test {
public static void test() {
System.out.println("Hello World!");
}
}
java
//B模块中定义
public class Main {
public static void main(String[] args) {
Test.test();
}
}
java
//C模块中定义
public class Main {
public static void main(String[] args) {
Test.test(); //找不到类Test,编译失败
}
}
这就很奇怪了,在Maven中是完全可以实现传递依赖的,为什么到Gradle就不行了呢?这是因为implementation不支持依赖传递,因此,即使我们改变了B模块的依赖,此时C也无法通过传递的形式得到B包含的依赖,由于不需要处理传递依赖,在编译时只需要处理一层,因此速度会非常快,大部分情况下非常推荐使用implementation来进行依赖导入。
如果各位小伙伴需要实现传递依赖的效果,我们需要使用另一个插件提供的方法来导入依赖:
java
plugins {
`java-library` //java-library提供了传递依赖api函数
}
dependencies {
api(project(":common")) //与implementation效果一样,但是支持传递依赖
testImplementation(platform("org.junit:junit-bom:5.9.1"))
testImplementation("org.junit.jupiter:junit-jupiter")
}
此时,模块B的依赖由于使用了api进行导入,我们在模块C中无论是使用api导入还是implementation导入B,都可以使用B中api函数导入的依赖了。