Dependencies
依赖的方式
Gradle 中的依赖分别为直接依赖,项目依赖,本地jar 依赖。案例如下:
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' }
直接依赖:在项目中直接导入的依赖,就是直接依赖implementation org.apache.logging.log4j:log4j:2.17.2
上面是简写法,完整版写法如下:
implementation group: 'org.apache.logging.log4j', name: 'log4j', version: '2.17.2'
group/name/version 共同定位一个远程仓库,version 最好写一个固定的版本号,以防构建出问题,implementation 类似maven 中的依赖的scope,对比 maven 中的依赖:
<dependencies> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.12</version> <scope>compile</scope> </dependency> </dependencies>
项目依赖: 从项目的某个模块依赖另一个模块
implementation project(':subject01')
这种依赖方式是直接依赖本工程中的libary module,这个 libary module 需要在setting.gradle 中配置。
本地jar 依赖:本地 jar 文件依赖,一般包含以下两种方式
//直接依赖某文件 implementation files('libs/foo.jar', 'libs/bar.jar') //配置某文件夹作为依赖项 implementation fileTree(dir: 'libs', include: ['*.jar'])
依赖的下载
当执行 build 命令时,gradle 就会去配置的依赖仓库中下载对应的 Jar,并应用到项目中。
依赖的类型
类似于 Maven 的 scope 标签,gradle 也提供了依赖的类型,具体如下所示:
scope | 作用 |
compileOnly | 由java插件提供,曾短暂的叫provided,后续版本已经改成了compileOnly,适用于编译期需要而不需要打包的情况 |
runtimeOnly | 由 java 插件提供,只在运行期有效,编译时不需要,比如mysql 驱动包。,取代老版本中被移除的 runtime |
implementation | 由 java 插件提供,针对源码[src/main 目录] ,在编译、运行时都有效,取代老版本中被移除的 compile |
testCompileOnly | 由 java 插件提供,用于编译测试的依赖项,运行时不需要 |
testRuntimeOnly | 由 java 插件提供,只在测试运行时需要,而不是在测试编译时需要,取代老版本中被移除的testRuntime |
testImplementation | 由 java 插件提供,针对测试代码[src/test 目录] 取代老版本中被移除的testCompile |
providedCompile | war 插件提供支持,编译、测试阶段代码需要依赖此类jar 包,而运行阶段容器已经提供了相应的支持,所以无需将这些文件打入到war 包中了;例如servlet-api.jar、jsp-api.jar |
compile | 编译范围依赖在所有的 classpath 中可用,同时它们也会被打包。在gradle 7.0 已经移除 |
runtime | runtime 依赖在运行和测试系统的时候需要,在编译的时候不需要,比如mysql 驱动包。在 gradle 7.0 已经移除 |
api | java-library 插件提供支持,这些依赖项可以传递性地导出给使用者,用于编译时和运行时。取代老版本中被移除的 compile |
compileOnlyApi | java-library 插件提供支持,在声明模块和使用者在编译时需要的依赖项,但在运行时不需要。 |
api 与implementation 区别
如下所示:
编译时:如果 libC 的内容发生变化,由于使用的是 api 依赖,依赖会传递,所以 libC、libA、projectX 都要发生变化,都需要重新编译,速度慢,运行时:libC、libA、projectX 中的class 都要被加载。
编译时:如果libD 的内容发生变化,由于使用的是implemetation 依赖,依赖不会传递,只有libD、libB 要变化并重新编译,速度快,运行时:libC、libA、projectX 中的class 都要被加载。
依赖冲突及解决方案
依赖冲突是指 “在编译过程中, 如果存在某个依赖的多个版本, 构建系统应该选择哪个进行构建的问题”,如下所示:
A、B、C 都是本地子项目 module,log4j 是远程依赖。
编译时: B 用 1.4.2 版本的 log4j,C 用 2.2.4 版本的 log4j,B 和 C 之间没有冲突
打包时: 只能有一个版本的代码最终打包进最终的A对应的jar |war包,对于 Gradle 来说这里就有冲突了
案例演示:我们在 build.gradle 引入依赖库
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' }
修 改 build.gradle
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' }
如上所示:默认下,Gradle 会使用最新版本的 jar 包【考虑到新版本的 jar 包一般都是向下兼容的】,实际开发中,还是建议使用官方自带的这种解决方案。当然除此之外,Gradle 也为我们提供了一系列的解决依赖冲突的方法: exclude 移除一个依赖,不允许依赖传递,强制使用某个版本。
● 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' }
● 不允许依赖传递
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' }
在添加依赖项时,如果设置 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') //强制使用某个版本!!【官方建议使用这种方式】 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() }