前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >Maven实战进阶(01)面试官:Maven怎么解决依赖冲突?| 有几种解决方式

Maven实战进阶(01)面试官:Maven怎么解决依赖冲突?| 有几种解决方式

原创
作者头像
拉丁解牛说技术
发布2025-01-16 10:56:05
发布2025-01-16 10:56:05
2000
举报
文章被收录于专栏:Maven实战进阶Maven实战进阶

读书笔记:给负面情绪降温,再寻求解决冲突问题。常见负面情绪有愤怒、悲伤、恐惧三大类。细分有生气、不满、伤心、担忧、缺少安全感等。识别自己的情绪、中性表达你所听到、看到的事实,不主观臆测,准确表达自己的情绪。此外,也需要疏导对方情绪,最后达成情绪共鸣,再寻求化解分歧和误会,找到解决方案。


一、前言背景

二、Maven是什么?

2.1 三大常用核心功能之依赖管理

2.2 三大常用核心功能之仓库管理

2.3 三大常用核心功能之项目构建

三、依赖是什么?从哪来?放哪里?

3.1 依赖里的scope是什么,有什么用?

3.2 依赖不在Maven仓库,怎么办?

四、如何解决依赖冲突?

4.1 Maven默认的解决方式

4.2 手工解决方式

4.3 其他方式


一、前言背景

Maven是什么?在很多初中级研发印象里,Maven只是系统项目里的一个pom.xml文件,甚至连mvn clean package命令都逐渐模糊。而项目研发技术leader、架构师已经把依赖管理、插件配置、整个系统的devops管理都做好了。大部分时间,大家只需要专注迭代完成系统业务功能开发。

然而,所有能被广泛应用的技术组件,背后必有超凡的设计和值得深入探索的技术价值。如果时间允许+自己也有兴趣,可以深入理解它的核心原理以及高阶特性。这个对我们研发技术经验积累和架构设计能力提升有极大帮助。

知识传播分享,不分高下,各有千秋。最近喜欢以专栏的形式,持续连载分享某个框架原理,也是希望能和有缘刷到且有兴趣的朋友,一起深入交流学习分享。也希望未来可以轻松的写一点新版本特性、或者只针对某个技术要点、生产故障进行详细探讨。

话不多说,今天正式开始我们的《Maven实战进阶系列》之旅。保持一贯风格,行文尽可能通俗易懂、图文并茂,以核心架构原理开局,力争以实战demo进阶,最后愿我们学海无涯,所见皆有所获。

二、Maven是什么?

Apache Maven是基于项目对象模型(POM)概念的项目管理构建工具。具有跨平台、标准化、自动化等特性。对于我们日常项目研发来说,Maven就是一个通过pom.xml文件来管理我们依赖包、插件、项目基础信息、项目构建的一个高度标准自动化的管理平台。

如果要说说Maven三大最常用、最核心的功能,我选择依赖管理、仓库管理、项目构建。

2.1 三大常用核心功能之依赖管理

首先,依赖管理,就是我们在pom里进行的项目依赖包的管理。我们只需要将依赖的第三方组件信息,通过dependency进行引入,maven就自动帮我们下载对应包以及管理它的生命周期。

2.2 三大常用核心功能之仓库管理

maven仓库有三种,一个是maven的中央仓库、一个是私服、一个是本地仓库。

在我们安装好maven后,本地有个仓库。比如我maven安装目录是:/Users/xxxx/soft/maven3.6.3。在该目录下,有个.m2目录,里面的repository文件夹,就是本地仓库。

查看本地仓库依赖包信息:ls .m2/repository

第二个私服。在企业里,公司需要搭建一个私有的公共maven仓库,方便存放管理内部各个研发项目的版本。此外,maven的中央仓库,由于是部署在国外,国内访问速度慢且网络不稳定。私服的存在,可以作为一个依赖缓存,避免研发依赖引入出现重复下载。

第三个,maven官方中央仓库https://mvnrepository.com/。这里存放共享着maven社区众多主流开源组件。基本上我们想要的依赖,在中央仓库都能找到。

此外,有些小公司,或者不需要搭建maven私服的企业,可以让研发人员配置国内主流远程仓库,比如阿里、清华仓库源,下载速度都非常快。在.m2/settings.xml文件配置:

代码语言:txt
复制
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
                          https://maven.apache.org/xsd/settings-1.0.0.xsd">
      
      <mirrors>
    	<mirror>  
      		<id>alimaven</id>  
      		<name>aliyun maven</name>  
      		<url>http://maven.aliyun.com/nexus/content/groups/public/</url>  
      		<mirrorOf>central</mirrorOf>          
    	</mirror>  
      </mirrors>
</settings>

2.3 三大常用核心功能之项目构建

日常项目构建,从代码编写就已经开始,写代码引入的包类需要maven管理构建引入,此后代码编译测试、运行、打包等过程都是项目构建流程内容。

在maven里,项目构建和生命周期密切相关。甚至就是maven通过生命周期来统一管理项目的构建过程。可以说项目构建管理,就是maven的生命周期管理。生命周期包括:清理、编译、测试、打包、部署、发布等过程。应用也非常简单,直接是mvn 后加生命周期名字即可,比如:mvn clean package。

这块内容会非常多,开篇我们简单了解即可,后续出一篇文章专门讲生命周期这块。

三、依赖是什么?从哪来?放哪里?

依赖就是我们系统项目依赖的第三方组件,比如fastjson、commons-langs组件。

在2.1我们也说过,在pom里 的 进行引入。这些依赖包,maven首先会从本地.m2仓库查找,如果没有找到,就从配置的远程仓库里找,一般是公司私服。如果公司私服也没有,私服就从远程仓库里下载。下载之后,存放在本地仓库。

3.1 依赖里的scope是什么,有什么用?

依赖里,除了groupId,artifactId,version,还有一个scope标签。比如我们日常用来做测试用的junit、Springboot test插件:

代码语言:txt
复制
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <scope>test</scope>
    <version>3.8.2</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

这个scope标签,就是我们依赖包使用范围。它有6个范围:compile、provided、runtime、test、system、import。用的最多默认值complie。

如果scope是complie,那依赖包可以使用范围最广,从编译、测试、运行均会被应用。

而test,就是在我们test代码里可以使用。如果尝试在主代码main里使用scope为test的依赖,就会报错。

这块很有意思,如果时间允许,可以自己实践改不同scope去测试验证。

对我们来说,如果使用不多,其实这块不需要太关注,因为在我们去中央仓库查找时候,官方已经给了推荐默认值,我们直接使用即可。

3.2 依赖不在Maven仓库,怎么办?

现实里,有些特殊依赖包,并没有共享上传到maven的中央仓库、而且公司私服也没有。这种包,我们可以通过打包上传到私服。然后再在项目里引用。如果仅仅是本地使用,可以直接放到自己电脑Maven本地仓库。

四、如何解决依赖冲突?

在maven依赖管理里,什么是依赖冲突?

这个是初级开发、尤其是校招生面试的时候,经常被问到的基础问题。以及刚才所探讨的几个小问题。

依赖冲突,实际是多个组件依赖的同一个第三方组件,但是版本不一致问题。比如,项目引入了pring-boot-starter-log4j2、以及commons-logging组件,但是两者底层都依赖了log4j-core,且版本不一致:

spring-boot-starter-log4j2 ,依赖log4j-core 版本2.23.1。

commons-logging 也依赖了log4j-core ,但是版本2.24.3。

4.1 Maven默认的解决方式

Maven对依赖冲突解决很简单:依赖版本不一致,就进行N选1(gradle更简单,直接是取最新版本为准)。不过这个N选1,maven有2个原则:

第一声明优先原则。在pom文件里,哪个依赖所处位置更靠前,就是优先声明,默认被引入进来。后续的冲突依赖,就不会被依赖进来(除非手工解决干预)。

路径最近优先原则。依赖是有传递性的,比如项目直接依赖了A组件V1.0、B组件。而B组件依赖了A组件的V2.0。由于V1.0的A组件,是被项目直接引入,那A组件的V1.0被引入。冲突的V2.0不会被引入。

4.2 手工解决方式

对于冲突依赖,maven支持手工依赖排除,通过exclusion标签去设置。比如:

代码语言:txt
复制
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <artifactId>accessors-smart</artifactId>
            <groupId>net.minidev</groupId>
        </exclusion>
    </exclusions>
</dependency>

此外,手工指定版本。有点类似4.1说的路径最近优先原则。比如项目直接引入依赖A、B组件。而A和B分别依赖C的V1和V2版本。这时候我们可以直接在项目里引入C组件,并指定对应版本来解决冲突。

4.3 其他方式

比如我们内部自研基础组件项目服务A依赖是pinyin4j。当我们打包服务A给其他项目使用,避免依赖pinyin4j给其他服务造成影响,我们设置pinyin4j的依赖进行依赖阻断。依赖阻断就是通过 设置为true来实现。比如:

代码语言:txt
复制
<dependency>
    <groupId>com.belerweb</groupId>
    <artifactId>pinyin4j</artifactId>
    <version>2.5.1</version>
    <optional>true</optional>
</dependency>

这样就可以避免其他服务在应用我们的基础组件时,需要手工解决依赖冲突问题。

推荐阅读拉丁解牛相关专题系列(欢迎交流讨论公众号搜:拉丁解牛说技术)


1、JVM进阶调优系列(5)CMS回收器通俗演义一文讲透FullGC

2、JVM进阶调优系列(4)年轻代和老年代采用什么GC算法回收?

3、JVM进阶调优系列(3)堆内存的对象什么时候被回收?

4、JVM进阶调优系列(2)字节面试:JVM内存区域怎么划分,分别有什么用?

5、JVM进阶调优系列(1)类加载器原理一文讲透

6、JAVA并发编程系列(13)Future、FutureTask异步小王子

7、MySQL进阶突击系列(05)突击MVCC核心原理 | 左右护法ReadView视图和undoLog版本链强强联合

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、前言背景
  • 二、Maven是什么?
    • 2.1 三大常用核心功能之依赖管理
    • 2.2 三大常用核心功能之仓库管理
    • 2.3 三大常用核心功能之项目构建
  • 三、依赖是什么?从哪来?放哪里?
    • 3.1 依赖里的scope是什么,有什么用?
    • 3.2 依赖不在Maven仓库,怎么办?
  • 四、如何解决依赖冲突?
    • 4.1 Maven默认的解决方式
    • 4.2 手工解决方式
    • 4.3 其他方式
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档