【Java项目管理工具】Gradle

Gradle

一、简介

Gradle 是一款 Google 推出的基于 JVM、通用灵活的项目构建工具,支持 Maven,JCenter 多种第三方仓库;支持传递性依赖管理、废弃了繁杂的 xml 文件,转而使用简洁的、支持多种语言(例如:java、C++、groovy 等)的 build 脚本文件。

在这里插入图片描述

该篇文章将从头到尾详述 gradle 项目流程配置及 gradle 基础知识(groovy语言版本),以及文件配置。同时强烈推荐结合官网文档教程进行学习。这里将不会介绍自定义任务、自定义插件等,如需编写此类代码,建议看官网教程。

官网教程:https://docs.gradle.org/current/userguide/getting_started_eng.html#gradle_intro

二、安装和配置

官网下载:https://gradle.org/

  1. 下载后解压即可

  2. 配置 Gradle 环境变量,配置 GRADLE_USER_HOME 环境变量(该环境变量即本地仓库地址和 Gradle Wrapper 缓存地址,可以但没必要与 maven 配置同一地址,因为存储依赖包的方式不一样),之后执行 gradle -v 即可测试是否成功配置

  3. 功能配置,在 gradle-8.5\init.d 目录添加 init.gradle 初始化配置文件

    • 在 gradle 的 init.d 目录下创建以 .gradle 结尾的文件,.gradle 文件会在 build 开始之前执行,所以可以在这个文件配置一些想预先加载的操作
    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 文件的方法有:加载顺序由上至下,相同目录不同文件配置会以字母顺序 a-z 的顺序执行

  1. 在命令行指定文件,例如:gradle --init-script yourdir/init.gradle -q taskName。可以多次输入此命令来指定多个init文件
  2. init.gradle 文件放到 USER_HOME/.gradle/ 目录下
  3. 把以 .gradle 结尾的文件放到 USER_HOME/.gradle/init.d/ 目录下
  4. 把以 .gradle 结尾的文件放到 GRADLE_HOME/init.d/ 目录下

【拓展】仓库地址说明

  • mavenLocal():指定使用maven本地仓库,而本地仓库在配置maven时settings文件指定的仓库位置。如E:/repository,gradle 查找jar包顺序如下:USER_HOME/.m2/settings.xml >> M2_HOME/conf/settings.xml >> USER_HOME/.m2/repository
  • maven { url 地址}:指定maven仓库,一般用私有仓库地址或其它的第三方库【比如阿里镜像仓库地址】
  • mavenCentral():这是Maven的中央仓库,无需配置,直接声明就可以使用

【拓展】grade缓存目录:grade 下载的 jar 不是存储在本地maven仓库中,而是放在自己的缓存目录中,默认在 USER_HOME/.gradle/caches 目录。如配置了 GRADLE_USER_HOME 则在 GRADLE_USER_HOME/caches 目录,且存储结构与 maven 本地仓库存储结构不同

阿里云仓库地址:https://developer.aliyun.com/mvn/guide

三、Grade项目

3.1 Wrapper 包装器

Gradle Wrapper 实际上是标准化 Gradle 项目的一种手段,通过 Gradle Wrapper 脚本定义了 Gradle 版本,并会在必要时提前下载,以确保用户使用的都是同一版本的 Gradle,这也是官方强烈鼓励使用的做法。只是一般我们还是会选择使用自己安装的 gradle

gradlewgradlew.bat 的使用方式与 gradle 使用方式完全一致,只是把 gradle 指令换成了 gradlew 指令。

gradle-wrapper.properties 定义了 gradle-wrapper 的下载目录,解压目录等

3.2 Idea 中创建 Gradle 项目

  1. 新建 Gradle 项目即可,创建完后会默认使用 gradle wrapper

  2. 一般建议修改为本地的: Settings -> Build, Execution, Deployment -> Build Tools -> Gradle 右边 DistributionWrapper 改为 Local installation 并确认 gradle 位置是否正确即可

  3. 如果还需要转为 web 项目,将 build.gradle 中的 plugins.id 修改为 war

    plugins {
        id 'war'
    }
    
  4. 重载 gradle 项目,打开 Project Structure ,点击 Web Gradle ,先复制 Web Resource Directories 部分爆红的路径

  5. 点击上面 Deployment Descriptors 中的 + 添加 web.xml 文件,版本选择看下面关系对应

Servlet VersionEE Version
6.1Jakarta EE ?
6.0Jakarta EE 10
5.0Jakarta EE 9/9.1
4.0JAVA EE 8
3.1JAVA EE 7
3.1JAVA EE 7
3.0JAVAEE 6
  • Tomcat 版本和Servlet版本之间的对应关系
Servlet Version**Tomcat ** VersionJDK Version
6.111.0.x17 and later
6.010.1.x11 and later
5.010.0.x (superseded)8 and later
4.09.0.x8 and later
3.18.5.x7 and later
3.18.0.x (superseded)7 and later
3.07.0.x (archived)6 and later (7 and later for WebSocket)

3.3 项目目录结构

在这里插入图片描述

四、Gradle 构建生命周期

4.1 构建的三大阶段

首先需要明白,这里的生命周期不同于 Maven 只是指对应命令的生命周期,这里的生命周期是指 gradle 构建的不同阶段。

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

  1. Initialization (初始化)阶段:主要目的是初始化构建, 它分为两个子过程,执行 Init Script 和执行 Setting Script
  2. Configuration (配置)阶段:加载项目中所有模块的 Build Script 。所谓 “加载” 就是加载 build.gradle 中的语句。根据脚本代码创建对应的 task,最终根据所有 task 生成由 task 组成的有向无环图
  3. Execution (执行)阶段:这个阶段会根据上个阶段构建好的有向无环图,按顺序执行(可并行) task【Action 动作】

对于 gradle 来说,项目都是一系列的 Task对象 的集合

在这里插入图片描述

4.2 生命周期中的 hook(钩子)函数

生命周期中的这些钩子函数都是由 gradle 自动回调完成的,利用这些钩子函数可以帮助我们实现一些我们想要的功能。

在这里插入图片描述

Gradle 初始化阶段

  • settings.gradle 执行完后,会回调 Gradle 对象的 settingsEvaluated 方法
  • 在构建所有工程 build.gradle 对应的 Project 对象后,也既初始化阶段完毕,会回调 Gradle 对象的 projectsLoaded 方法

Gradle 配置阶段

  • Gradle 会循环执行每个工程的 build.gradle 脚本文件
  • 在执行当前工程 build.gradle 前,会回调 Gradle 对象的 beforeProject 方法和当前 Project 对象的 beforeEvaluate 方法。虽然 beforeEvalute 属于 project 的生命周期, 但是此时 build script 尚未被加载, 所以 beforeEvaluate 的设置依然要在 init scriptsetting script 中进行,不要在 build script 中使用 project.beforeEvaluate 方法
  • 在执行当前工程 build.gradle 后,会回调 Gradle 对象的 afterProject 方法和当前 Project 对象的 afterEvaluate 方法
  • 在所有工程的 build.gradle 执行完毕后,会回调 Gradle 对象的 projectsEvaluated 方法
  • 在构建 Task 依赖有向无环图后,也就是配置阶段完毕,会回调 TaskExecutionGraph 对象的 whenReady 方法

Gradle 执行阶段

  • Gradle 会循环执行 Task 及其依赖的 Task
  • 在当前 Task 执行之前,会回调 TaskExecutionGraph 对象的 beforeTask 方法
  • 在当前 Task 执行之后,会回调 TaskExecutionGraph 对象的 afterTask 方法
  • 当所有的 Task 执行完毕后,会回调 Gradle 对象的 buildFinish 方法

提示:Gradle 执行脚本文件的时候会生成对应的实例,主要有如下几种对象:

  1. Gradle 对象:在项目初始化时构建,全局单例存在,只有这一个对象
  2. Project 对象:每一个 build.gradle 文件 都会转换成一个 Project 对象,类似于maven中的pom.xml文件
  3. Settings 对象settings.gradle 会转变成一个 settings 对象,和整个项目是一对一的关系
  4. Task对象: gradle最终是基于Task的,一个项目可以有一个或者多个Task

五、Task

Gradle 项目实质上是 Task 对象的集合。一个 task 表示一个逻辑上较为独立的执行过程,比如编译 Java 源代码,拷贝文件,打包 Jar 文件,甚至可以是执行一个系统命令。如执行 gradle clean ,实质是执行 clean 及其依赖任务,一系列任务的执行最终达到与 mvn clean 执行后类似影响的效果。任务来自构建脚本插件

5.1 任务的执行及常用任务

查看项目所有可用任务:gradle tasks

任务执行语法:gradle [taskName...] [option-name...]

Gradle 常用命令 :需要注意的是:gradle 的指令要在含有 build.gradle 的目录执行才会对对应项目产生效果

命令描述
gradle clean清理编译或打包后的项目结构,即 build 目录
gradle class编译项目,生成 build 目录及内容
gradle test执行测试源码,生成测试报告
gradle build打包项目,生成jar或war文件
gradle build -x test跳过测试,直接打包
gradle run运行一个应用,需要 application 插件支持,并且需指定主启动类

项目报告相关任务

命令描述
gradle projects列出所选项目及子项目列表,以层次结构的形式显示
gradle tasks列出所选项目【当前项目,不包含父、子】的已分配给任务组的任务
gradle tasks --all列出所选项目的所有任务
gradle tasks --group=“build setup”列出所选项目中指定分组中的任务
gradle help --task someTask显示某个任务的详细信息
gradle dependencies查看整个项目的依赖信息,以依赖树的方式显示

部分常见参数

参数描述
-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 项目(根目录执行)

还有其他附加调试、性能、守护进程、日志等 option 参数,需要的自行查阅。

【拓展】gradle 任务名可以是缩写: 任务名支持驼峰式命名风格的任务名缩写,如:connectTask 简写为:cT,执行任务 gradle cT

5.2 任务的依赖及执行顺序

一个任务需要先运行另一个任务,例如,要让 Gradle 执行任务 build ,必须首先编译 Java 代码。因此,build 任务取决于任务 compileJava

gradle 默认各指令之间的依赖关系:

在这里插入图片描述

相关解释

在这里插入图片描述

六、settings.gradle 文件

Gradle Build 生命周期中的 Initialization (初始化)阶段使用 settings.gradle 文件查找工程根目录中包含的根工程和子工程,创建一个 Settings 实例,并为每个工程创建一个 Project 实例。

settings.gradle 文件是每个 Gradle 项目的入口点。对于单工程构建可不设置,对于多工程构建则是必须的(这里的工程可理解为 idea 中的 module)。

该文件的主要配置类似于 maven 中父工程的 module 标签,每个项目只有一个 settings.gradle文件 。与 Maven 一样,在 Idea 中增加子工程时,会自动配置。

看一个 settings.gradle 文件的例子,并分解各个功能如下:一般而言,这个配置文件中只包含 类似 module 模块内容,但是以下例子来源官网,故对应标签的解释也放在这里,实际上其他标签一般写在 build.gradle

pluginManagement { // 1. 定义插件库,还可以在此块中包含插件和插件依赖项解析策略,该块必须是第一个块
    repositories { // 1.1 下面各个库按顺序查找
        maven {
            url './maven-repo'
        }
        gradlePluginPortal()
        google()
    }
    plugins { // 2. 插件版本管理,则在 build.gradle 中只需要写 id 'com.example.hello' 即可
        id 'com.example.hello' version "${helloPluginVersion}"
        id 'org.gradle.toolchains.fake' version '0.6.0'
    }
}

dependencyResolutionManagement { // 3. 定义依赖存储库,可以选择使用 Maven Central 等二进制存储库来定义项目所依赖的组件的位置(以及如何解析它们)
    repositories {
        mavenCentral()
    }
}

// 4. 类似 maven 的 module 标签部分
rootProject.name = 'root' // 定义根项目名称,每个构建只有一个根项目。
include 'subject01' // 包含的子工程目录,注意是目录
include 'subject01:subproject011' //包含的子工程下的子工程目录

七、build.gradle 文件

Initialization (初始化)阶段,gradle 根据 settings.gradle 文件为每个工程创建 Project 实例后,在 Configuration (配置)阶段会查找对应实例的 build.gradle 脚本文件,进行工程构建。

  • build.gradle 可以是 Groovy 编写的文件,也可以是用 Kotlin 编写的文件。具体使用类似于 maven 的 pom.xml 但又不仅限于配置
  • 每个 build 文件都有一个对应的 Project 实例。对 build.gradle 文件配置,本质就是设置 Project 实例的属性和方法
  • Gradle 会隐式向脚本添加一组 import org.gradle.* 的语句,所以在使用很多方法时无需引入

以下是创建的一个 build.gradle 的案例:

plugins { // 1. 将插件应用到构建中
    id 'org.jetbrains.kotlin.jvm' version '1.9.0'
    id 'application' // 应用 application 插件会隐式应用 Java 插件,并将 assemble 和 build 等任务添加run到我们的项目中
}

repositories { // 2. 定义依赖库
    mavenCentral()
}

group = 'org.example'
version = '1.0-SNAPSHOT'
compileJava.options.encoding = "UTF-8"

dependencies { // 3. 添加依赖项
    testImplementation 'org.jetbrains.kotlin:kotlin-test-junit5'
    testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.9.3'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
    implementation 'com.google.guava:guava:32.1.1-jre'
}

java {
    toolchain {
        languageVersion.set(JavaLanguageVersion.of(17))	// 4. 定义 jdk 版本
    }
}

application { // 5. 设置属性,应用程序的主类
    mainClass = 'com.example.Main'
}

tasks.named('test') { // 6. 注册并配置任务,或者使用 tasks.register() 方法
    useJUnitPlatform()
}

7.1 常见属性和方法

在这里插入图片描述

//指定使用什么版本的JDK语法编译源代码,跟编译环境有关,在有java插件时才能用,官方推荐开头案例中使用的工具链 toolchain
sourceCompatibility = 1.8
//指定生成特定于某个JDK版本的class文件:跟运行环境有关,在有java插件时才能用
targetCompatibility = 1.8
//业务编码字符集,注意这是指定源码解码的字符集[编译器]
compileJava.options.encoding "UTF-8"
//测试编码字符集,注意这是指定源码解码的字符集[编译器]
compileTestJava.options.encoding "UTF-8"
//编译JAVA文件时采用UTF-8:注意这是指定源码编码的字符集【源文件】
tasks.withType(JavaCompile) {
    options.encoding = "UTF-8"
}
//编译JAVA文件时采用UTF-8:注意这是指定文档编码的字符集【源文件】
tasks.withType(Javadoc) {
    options.encoding = "UTF-8"
}

当本地终端运行 gradle 项目输出乱码时,可尝试设置上面对应编码解决问题。

7.2 plugins(插件)

gradle 的大多数功能是通过 插件 添加的,插件可以提供有用的任务,例如运行代码、创建文档、设置源文件、发布档案等。可以通过 gradle tasks (查看可用任务) 查看加入某个插件前后的区别。

7.2.1 插件的分类与使用

核心插件只需要基于 plugin id 来声明即可,而社区的插件的引入则必须基于 plugin idplugin version 来共同声明

  • 脚本插件:本质就是一个脚本文件,即可以将脚本文件模块化,在 build.gradle 中使用 apply from: 'xxx.gradle' 即可导入脚本插件
  • 二进制插件 :就是实现了 org.gradle.api.Plugin 接口的插件,每个插件都有一个 plugin id ,二进制插件还可以细分为一下三类

插件的使用方式:主要分为 applyplugins DSL 方式两种。推荐用 DSL 方式

  1. 对于内部插件:如 org.gradle.api.plugins.JavaPlugin
apply plugin:org.gradle.api.plugins.JavaPlugin // 使用方式1:Map具名参数,全类名
apply plugin:JavaPlugin						   // 使用方式2:org.gradle.api.plugins默认导入
apply plugin: 'java'						   // 使用方式3:插件的id
// 使用方式4:plugins DSL
plugins {
    id 'java'
}
  1. 对于第三方插件 :如 SpringBoot ,有两种使用方式,一是传统的 buildscript 方式,一种是 plugins DSL 方式,第二种方式要求第三方插件已被托管
// 方式一:使用传统的应用方式,必须是文件首个块
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' //社区插件,需要事先引入,不必写版本号

如果第三方插件已被托管到 https://plugins.gradle.org/ ,则可使用 plugins DSL 方式直接引入

// 方式二:DSL,必须是文件的首个块
plugins {
    id 'org.springframework.boot' version '2.3.3'
}

7.2.2 插件的关注点——Java插件为例

当需要使用一个插件时,需关注以下几点,这里以 Java 插件为例分析:

  1. 插件的引入方式

    plugins {
        id 'java'
    }
    
  2. 插件的功能:当加入 java 插件之后,就加入了如下功能

    在这里插入图片描述

  3. 插件约定的工程目录结构 :有的插件对工程目结构有约定,所以一般遵循它的约定结构来创建工程,这也是 Gradle 的“约定优于配置”原则。如 Java 插件,当然一般默认结构也可修改。但一般不推荐修改:

    在这里插入图片描述

  4. 依赖管理 :以 java 插件为例,提供了很多依赖管理项。依赖项是指支持构建项目的 JAR、插件、库或源代码。

    • 源集依赖关系配置

      在这里插入图片描述

    • 测试源集依赖关系配置

      在这里插入图片描述

  5. 扩展的属性和方法 :以 Java 插件为例,常用目录属性及方法

    java {
        toolchain {
            languageVersion = JavaLanguageVersion.of(17)
        }
    }
    
    属性或方法类型默认值描述
    toolchain构建JVM工具链Java 工具链供使用 JVM 工具的任务使用,例如编译和执行。
    withJavadocJar()方法javadocElements 自动打包 Javadoc 并创建带有工件的变体-javadoc.jar,该文档将成为产出的一部分
    withSourcesJar()方法自动打包源代码并创建 sourceElements 带有工件的变体-sources.jar,该工件将成为出版物的一部分。
    reporting.baseDirStringreports生成报告的目录名称
    testResultsDirNameStringtest-results生成测试结果 .xml 文件的目录名称
    testReportDirNameStringtests生成测试报告的目录名称
    libsDirNameStringlibs生成库的目录名称
    distsDirNameStringdistributions生成发行版的目录名称
    docsDirNameStringdocs生成帮助文档的目录名称
    dependencyCacheDirNameStringdependency-cache用于缓存相对于构建目录的源依赖信息的目录的名称
    archivesBaseNameString项目名生成的 jar 包 或 zip 包的基本名称

7.3 Repositories

该代码块用于配置依赖仓库,因为 Gradle 没有自己的远程仓库,而是使用 Maven、jcenter、jvy、google 这些远程仓库。

  • repositories {} 块中,gradle中会按着仓库配置的顺序,从上往下依次去对应的仓库中找所需要的jar包
repositories {
	// 指定去本地某个磁盘目录中查找:使用本地file文件协议:一般不用这种方式
	maven { url 'file:///D:/repos/mavenrepos3.5.4'}
    maven { url "$rootDir/lib/release" }
	//指定去maven的本地仓库查找
	mavenLocal()
	//指定去maven的私服或者第三方镜像仓库查找
	maven { name "Alibaba" ; url "https://maven.aliyun.com/repository/public" }
    maven { name "Bstek" ; url "https://nexus.bsdn.org/content/groups/public/" }
	//指定去maven的远程仓库查找:即 https://repo.maven.apache.org/maven2/
    mavenCentral()
    //去google仓库查找
    google()
}

7.4 Dependencies

该块中配置项目的依赖,通过 gradle dependencies 命令,可查看项目的依赖树

7.4.1 依赖的方式

  • 直接依赖:在项目中直接导入的依赖,就是直接依赖;
  • 项目依赖:项目的某个模块依赖另一个模块
  • 本地 jar 依赖:本地 jar 文件依赖,两种方式,文件依赖和文件目录依赖
dependencies {
    // 1. 直接依赖,group:name:version 共同定位一个远程仓库,version 最好写一个固定的版本号,以防构建出问题
    implementation 'org.apache.logging.log4j:log4j:2.17.2'
    // 2. 依赖当前项目下的某个模块[子工程]
    implementation project(':subject01')
    // 3. 直接依赖本地的某个jar文件
    implementation files('libs/foo.jar', 'libs/bar.jar')
    // 4. 配置某文件夹作为依赖项
    implementation fileTree(dir: 'libs', include: ['*.jar'])
}

7.4.2 依赖的类型

依赖的类型类似于 Maven 的 scope 标签,即对应着依赖的作用范围,有编译环境、测试环境、运行环境,类型具体如下:

类型名描述
compileOnlyjava插件提供。曾短暂的叫 provided ,后续版本改成了 compileOnly ,适用于编译期需要而不需要打包的情况
runtimeOnlyjava插件提供。只在运行期有效,编译时不需要,如:mysql 驱动包。取代老版本 runtime
implementationjava 插件提供。针对源码[src/main 目录] ,在编译、运行时都有效。取代老版本 compile
testCompileOnlyjava 插件提供。用于编译测试的依赖项,运行时不需要
testRuntimeOnlyjava 插件提供。只在测试运行时需要,而不是在测试编译时需要。取代老版本 testRuntime
testImplementationjava 插件提供。针对测试代码[src/test 目录]。取代老版本 testCompile
providedCompilewar 插件提供支持,编译、测试阶段代码需要依赖此类 jar 包,而运行阶段容器已经提供了相应的支持,所以无需将这些文件打入到 war 包中了。如 servlet-api.jarjsp-api.jar
compile编译范围依赖在所有的 classpath 中可用,同时它们也会被打包。 gradle 7.0 已经移除
runtime在运行和测试系统的时候需要,在编译的时候不需要,比如 mysql 驱动包。 gradle 7.0 已经移除
apijava-library 插件提供支持,这些依赖项可以传递性地导出给使用者,用于编译时和运行时。取代老版本中被移除的 compile
compileOnlyApijava-library 插件提供支持,在声明模块和使用者在编译时需要的依赖项,但在运行时不需要

【提示】java 插件提供的功能,java-library 插件都提供

7.4.3 api 和 implementation 的区别

主要区别就是 api 可以进行依赖传递,implementation 不会进行依赖传递。

有 A、B、C、D四个模块:

  • A implemetation B,B implemetation C,则A不能使用C
  • A implemetation B,B api C,则A可以使用C
  • A implemetation B,B implemetation C,C api D,则 B 可以使用 D ,但 A 不能使用
  • A implemetation B,B api C,C api D,这样A可以使用D
  • 不管ABCD在何处被添加到类路径都一样,在运行时这些模块中的class都是要被加载的
apiimplementation
编译时能进行依赖传递,底层变,全部都要变、编译速度慢不能进行依赖传递,底层变,不用全部变,编译速度快
运行时运行时会加载,所有模块的 class 都要被加载运行时会加载,所有模块的 class 都要被加载
应用场景适用于多模块依赖,避免重复依赖模块多数情况下使用 implementation

总之,除非涉及到多模块依赖,为了避免重复依赖,可以使用 api。其它情况优先选择 implementation ,拥有大量的 api 依赖项会显著增加构建时间

7.4.4 依赖冲突及解决方案

依赖冲突是指 “在编译过程中, 如果存在某个依赖的多个版本, 构建系统应该选择哪个进行构建的问题”

假设 A -> B -> log4j 1.4.2 ,A -> C -> log4j 2.2.4 。A、B、C 都是本地子项目 module,log4j 是远程依赖

  • 编译时: B 用 1.4.2 版本的 log4j,C 用 2.2.4 版本的 log4j,B 和 C 之间没有冲突
  • 打包时: 只能有一个版本的代码最终打包进最终的A对应的 jar | war 包,对于 Gradle 来说这里就有冲突了

默认情况下,Gradle 会使用最新版本的 jar 包。建议使用官方自带的这种解决方案。

除此之外,还有一系列解决依赖冲突的方法:

1. Exclude 排除某个依赖
dependencies {
	testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
    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'
}
2. 关闭依赖传递

设置 transitive(false) ,关闭依赖传递。即内部的所有依赖将不会添加到编译和运行时的类路径

dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
    implementation('org.hibernate:hibernate-core:3.6.3.Final'){
        //不允许依赖传递,一般不用
        transitive(false)
    }
    //排除之后,使用手动的引入即可
    implementation 'org.slf4j:slf4j-api:1.4.0'
}
3. 强制使用某个版本
dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
    implementation('org.hibernate:hibernate-core:3.6.3.Final')
    //强制使用某个版本!!【官方建议使用这种方式】
    implementation('org.slf4j:slf4j-api:1.4.0!!')
    //这种效果和上面那种一样,强制指定某个版本
    implementation('org.slf4j:slf4j-api:1.4.0'){
        version{
            strictly("1.4.0")
        }
    }
}
4. 查看当前项目依赖冲突
//配置当 Gradle 构建遇到依赖冲突时,就立即构建失败
configurations.all() {
    Configuration configuration ->
    //当遇到版本冲突时直接构建失败
    configuration.resolutionStrategy.failOnVersionConflict()
}

7.5 Subprojects 与 Allprojects

allprojects 是对所有 project(包括 Root Project+ child Project[当前工程和所有子工程])的进行统一配置

subprojects 是对所有 Child Project 的进行统一配置

allprojects {
    tasks.create('hello') {
        doLast { 
            task ->
            println "project name is $task.project.name"
        }
    }
}
subprojects {
    hello.doLast{
        task->
        println "here is subprojects $task.project.name"
    }
}

八、微服务配置案例

一个仅供参考的案例

8.1 项目架构

在这里插入图片描述

  • microservice-parent: 统一管理所有模块的 jar 包版本信息
  • microservice-bean: 统一管理所有模块的用到的 pojo 类
  • microservice-common:统一管理所有模块的用到的工具类、枚举类、异常处理、日志文件、统一返回结果信息
  • microservice-service: 统一封装所有的微服务
  • microservice-gateway: 封装网关信息

8.2 settings.gradle

rootProject.name = 'microservice'
include 'microservice_bean'
include 'microservice_common'
include 'microservice_gateway'
include 'microservice_service'
include 'microservice_service:service_user'
findProject(':microservice_service:service_user')?.name = 'service_user'
include 'microservice_service:service_order'
findProject(':microservice_service:service_order')?.name = 'service_order'

8.3 version.gradle

// 依赖版本管理
ext {
    version = [
            "fastjsonVersion"   : "1.2.72",
            "mybatisPlus" : "3.0.5",
            "mysql" : "5.1.46",
            "swaggerVersion": "2.7.0",
            "jjwtVersion": "0.7.0"
    ]

    dependencies = [
            "fastjson"                      : "com.alibaba:fastjson:${version.fastjsonVersion}",
            "mybatis-plus-boot-starter"     : "com.baomidou:mybatis-plus-boot-starter:${version.mybatisPlus}",
            "mysql"                         : "mysql:mysql-connector-java:${version.mysql}",
            "swagger"                       : "io.springfox:springfox-swagger2:${version.swaggerVersion}",
            "swaggerUI"                     : "io.springfox:springfox-swagger-ui:${version.swaggerVersion}",
            "jjwt"                          : "io.jsonwebtoken:jjwt:${version.jjwtVersion}"
    ]
}

8.4 build.gradle

description '父工程'

//构建Gradle脚本自身需要的资源,可以声明的资源包括依赖项、第三方插件、maven仓库地址等。
buildscript {
    ext {
        springBootVersion = '2.2.1.RELEASE'
        springCloudVersion = 'Hoxton.RELEASE'
        springCloudAlibabaVersion = '0.2.2.RELEASE'
    }

    //设置仓库
    repositories {
        maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' }
        maven { url 'https://repo.spring.io/milestone'}
    }

    dependencies {
        // 使用 spring-boot-gradle-plugin 插件便不再需要关心这两个插件的依赖关系,只需关注于 springboot 的版本
        // id 'org.springframework.boot' version '2.3.7.RELEASE' //维护springboot版本号,不单独使用,和下面两个插件一起用
		// id 'io.spring.dependency-management' version '1.0.10.RELEASE' //进行依赖管理,在引入其它boot依赖时省略版本号、解决jar包冲突问题
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

//配置全局, 包括root项目和子项目
allprojects {
    group 'com.atguigu'
    version '1.0-SNAPSHOT'

    //配置编码格式
    tasks.withType(JavaCompile) {
        options.encoding = "UTF-8"
    }

    //设置仓库
    repositories {
        maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' }
        maven { url 'https://repo.spring.io/milestone'}
    }

}

apply from: 'version.gradle'

//配置所有子项目
subprojects {

    apply plugin: 'java'
    apply plugin: 'java-library' //api
    apply plugin: 'io.spring.dependency-management'

    sourceCompatibility= JavaVersion.VERSION_1_8
    targetCompatibility=  JavaVersion.VERSION_1_8

    //公用的依赖
    dependencies {
        testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
        testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
    }

    test {
        useJUnitPlatform()
    }

    // dependencyManagement版本统一管理,类似于父maven的dependencyManagement
    dependencyManagement {
        dependencies {
            for(depJar in rootProject.ext.dependencies){
                dependency depJar.value
            }
        }
        imports {
            mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
            mavenBom "org.springframework.cloud:spring-cloud-alibaba-dependencies:${springCloudAlibabaVersion}"
        }
    }
}


project(':microservice_bean'){
    description("尚硅谷微服务实战之bean层:存放表对应的实体类")
}

project(":microservice_common"){
    description("尚硅谷微服务实战之公共模块:存放微服务常用的工具类")
    //依赖
    dependencies {
        api 'com.alibaba:fastjson'
        api 'mysql:mysql-connector-java'
        api 'com.baomidou:mybatis-plus-boot-starter'
        api 'io.springfox:springfox-swagger2'
        api 'io.springfox:springfox-swagger-ui'
        api 'io.jsonwebtoken:jjwt'

        api 'org.springframework.cloud:spring-cloud-starter-openfeign'
        api 'org.springframework.cloud:spring-cloud-starter-alibaba-sentinel'
        api 'org.springframework.cloud:spring-cloud-starter-alibaba-nacos-discovery'

    }
}

project(":microservice_service"){
    description("尚硅谷微服务实战之服务模块:存放各个微服务模块")
    apply plugin: 'org.springframework.boot'

    subprojects {
        apply plugin : 'java-library'
        apply plugin: 'org.springframework.boot'

        dependencies {
            api 'org.springframework.boot:spring-boot-starter-web'
            api project(':microservice_bean')
            api project(':microservice_common')
        }
    }

}
  • 25
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值