gradle的依赖管理和版本冲突的解决

gradle的依赖管理和版本冲突的解决
gradle的依赖管理和版本冲突的解决
参考⽂档:
⼀、依赖管理
  ⼏乎所有基于 JVM 的软件项⽬都需要依赖外部的类库来重⽤现有的功能代码.⾃动化依赖管理可以明确依赖的版本,能解决传递性依赖带来的版本冲突问题.
  ⽽Gradle 就满⾜这两个条件,以下就来看下依赖管理的关键点.
1.1、项⽬坐标(jar 包为例)
group : 指明 jar 包所在的分组
name : 指明 jar 包的名称
version: 指明 jar 包的版本马铃薯馒头
1.1.1、如何定义依赖
⽅式1:依赖⼀个 project(或者说依赖⼀个 module)
⽅式2:依赖⼀个 jar 包
⽅式2:扩展:通过 fileTree 依赖 dir ⽂件夹下所有的 jar 包
⽅式3:依赖远程仓库
def jdkHome = v("JAVA_HOME")
dependencies {
//⽅式1:依赖⼀个名字为 "common" 的 project
compile project(":common")
//⽅式2:依赖⼀个本地 jar 包(jdk中lib⽬录的tools.jar)
compile files("$jdkHome/lib/tools.jar")
//⽅式2 扩展:通过 fileTree 指定 dir 依赖所有的 jar 包
compile fileTree(dir:'D:\\Work', include:['*.jar'])
//⽅式3:依赖⼀个远程仓库的包
compile 'junit:junit:4.12'
}
1.2、仓库(jar 包的存放位置)
公共仓库(中央仓库)
  Gradle 没有⾃⼰的中央仓库,可配置使⽤ Maven 的中央仓库:mavenCentral/jcenter
私有仓库
  配置从本地 maven 仓库中获取依赖的 jar 包,不远程加载 jar 包,使⽤ mavenLocal
⾃定义 maven 仓库
  ⾃定义仓库来源,⼀般指向公司的 Maven 私服.(普遍做法)
⽂件仓库
  本地机器上的⽂件路径,⼀般不使⽤,没有意义,因为构建⼯具的⽬的就是去除本机的影响,可以在任何地⽅公⽤同⼀份仓库数据,跟本机关联上就没有太⼤的意义,当然特殊情况下除外.
往复式喷漆机
repositories {
//  优先使⽤本地maven存储
mavenLocal()
//  然后使⽤⾃定义的阿⾥云maven私服溯源防伪
maven{
url 'maven.aliyun/repository/public/'
}
//  最后使⽤maven中央仓库
mavenCentral()
}
1.3、依赖传递性
  ⽐如: A 依赖 B,如果 C 依赖 A,那么 C 依赖 B
  就是因为依赖的传递性,所以才会出现版本的冲突问题.以下通过⼀张图来了解下Gradle 的⾃动化依赖管理流程.
  由图可得知,Gradle ⼯具从远程仓库下载 jar 包到本地仓库,Gradle ⼯具需要依赖配置⽂件,如果同⼀个 jar 经常使⽤会被存⼊到依赖缓存中.
1.4、依赖配置
  在 adle 中的 dependencies 中配置依赖,依赖分以下四种依赖.
源码依赖: compile , runtime
测试依赖: testCompile,testRuntime
  详细介绍:
compile 配置的jar,测试代码编译和运⾏以及源码运⾏⼀定存在
runtime 配置的jar,只有源码运⾏和测试运⾏存在
testCompile 配置依赖的jar,测试代码的源码和运⾏阶段存在
testRuntime 配置依赖的jar,只有测试代码的运⾏存在
  关系图如下:
  具体效果如下
  以上的四种配置选⽤的主要判断依据是是否仅是运⾏阶段需要依赖或是否仅是测试阶段需要依赖.runtime ,如果仅是测试阶段需要依赖加 test 前缀 testCompile 或 testRuntime.
1.4.1、Maven中其他配置属性:
    熟悉maven 的应该知道,依赖范围控制除了常⽤的:compile (编译,默认的scope)、runtime (运⾏时)、test (测试)之外;还有:provided (已提供)、system (系统)、import(导⼊)等,下⾯介绍⼀下相关配置:
provided:(编译时依赖,打包时并不打包)
  provided 依赖只有在当JDK 或者⼀个容器已提供该依赖之后才使⽤。例如, 如果你开发了⼀个web 应⽤,你可能在编译classpath 中需要可⽤的Servlet API 来编译⼀个servlet,但是你不会想要在打包好的WAR 中包含这个Servlet API;这个Servlet API JAR 由你的应⽤服务器或者servlet 容器提供。已提供范围的依赖在编译classpath (不是运⾏时)可⽤。它们不是传递性的,也不会被打包。
system:(依赖本地⽂件,systemPath标签指定⽂件路径)
  跟provided 相似,但是在系统中要以外部JAR包的形式提供,maven不会在repository查它。需通过外部引⼊,不会在仓库中查。例如⼀些特殊的jar我们或通过拷贝jar到web-info/lib下,这些jar就可以配置为system范围。同时必须提供⼀个systemPath标签,systemPath标签指定⽂件路径。
import:
  仅在多个项⽬的⽗项⽬中的 <dependencyManagement> 依赖项上,它表⽰要在指定的POM <depen
dencyManagement> 部分中⽤有效的依赖关系列表替换的依赖关系。该scope类型的依赖项实际上不会参与限制依赖项的可传递性。
  依赖传递
    当scope的作⽤域为:test、provided、system 时当前项⽬依赖JAR并不会被传递到依赖的项⽬中,其它配置时(compile、runntime)依赖将会传递到依赖的项⽬中。
    例如:有两个项⽬A、B,当前项⽬为B,B依赖于A,A项⽬中配置了dom4j的jar依赖,并将其配置属性设置为:compile,则B项⽬中会⾃动依赖A项⽬的 dom4j,如果配置为:provided,则B项⽬不会⾃动添加dom4j 的依赖。
  依赖隔断
    假设这种情况:A项⽬的dom4j配置了scope属性为 compile,但是⼜不想将当前依赖传递到依赖的B项⽬中,那就要考虑依赖隔断了。
    依赖隔断有两种⽅式:主动隔断和被动隔断,主动隔断:B项⽬通过配置来进⾏隔断,被动隔断:A项⽬配置属性表⽰当前依赖不传递。
  被动隔断
    在maven中经常会使⽤ <optional> true </optional> 参数让依赖只被当前项⽬使⽤,⽽不会在模块间进⾏传递依赖(A项⽬配置)。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
  主动隔断
    可以在B项⽬<dependency>的标签中通过 <exclusion> ⼦标签来主动的排除当前依赖。
<dependency>直埋蒸汽管道
<groupId>org.hibernate</groupId>
高压水冲<artifactId>hibernate-core</artifactId>
<version>3.6.3.Final</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
1.4.2、gradle中的其它配置
    gradle中除了上⾯介绍的⼏种配置之外,还有implementation、testImplementation、compileOnly
、testCompileOnly、compileClasspath、testCompileClasspath、runtimeOnly、testRuntimeOnly、runtimeClasspath、testRuntimeClasspath、
api(我当时使⽤的版本未到当前⽅法)等
1.4.
2.1、implementation和api的区别:
  gradle 从 3.4 开始,compile 已经被废弃了,取⽽代之的是 api | implementation,俩个我们都可以⽤,但是肯定还是有区别的:api - 本地依赖时依赖不隔离,但是编译慢
implementation - 本地依赖时依赖隔离,编译快
  依赖隔离:
超导限流器
    假设我本地有四个模块,分别为A、B、C、D, module A 依赖 module B ,module B ⼜依赖了 module C ,module C ⼜依赖了 module D;
    1. 本地 project 依赖
(api) A -> D 要是都是 api 的本地依赖⽅式,那么 A 中可以使⽤ B,C,D 的 API
(implementation ) A -> D 要是都是 implementation 的本地依赖⽅式,那么 A 就只能使⽤ B 的 API,C,D 的 API 是不到的
    2. 远程 maven 依赖
      implementation 就没代码隔离的作⽤了,B,C,D 的 API A 都能使⽤
    3. 远程和本地依赖混⽤
      若 C -> D 之间是远程依赖,但 A-> B -> C 之间是本地依赖, 使⽤ implementation 时,B 可以拿到 D 的 api,但是 A 就拿不到 D 的 api 了
  编译速度:
    在本地依赖时 implementation 可以起到代码隔离的作⽤,⾃然编译的速度就快,还是 A-> B -> C -> D 举例,若是 D 更新了,那么只有 C,D 是需要重新编译的。但是⼀旦我们使⽤了 API 的依赖⽅式,那么 ABCD 都需要重新编译
1.4.
2.2、compileOnly
  compileOnly和provided效果是⼀样的,只在编译的时候有效, 不参与打包
1.4.
2.3、runtimeOnly
  runtimeOnly 和 apk效果⼀样,只在打包的时候有效,编译不参与
1.4.
2.4、testImplementation
  testImplementation和testCompile效果⼀样,在单元测试和打包测试apk的时候有效
1.5、打包时将依赖也合并⼊jar包
  有些情形需要将项⽬依赖的jar包也合并⼊⾃⼰项⽬的jar包内,出来的这个jar我们称它为fat-jar。
  举个例⼦:我编写了⼀个 m3u8格式下载的jar⼯程,最后打包成了⼀个jar,想要通过 java -jar 的形式启动,其中项⽬使⽤到了HttpClient等,需要将其打包到项⽬的jar⽂件中。
  ⽅式⼀:⾃定义task来搞定
  有部分博客说这种打包⽅式有问题,但是本⼈测试发现⼀切正常(使⽤gradle版本为:6.2.2)

本文发布于:2024-09-23 19:16:33,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/2/178318.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:依赖   仓库   配置   编译
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议