maven 依赖冲突

一、问题

项目开发过程中,经常会遇到jar冲突,然后maven根据自己的规则进行冲突解决,导致项目在运行的过程中报错。

1、maven自动解决依赖冲突的规则是什么?

2、如何查看当前项目的maven的依赖树?

3、如何从依赖树中找到自己预期的版本,是被那个jar给覆盖了?

4、如何人工进行依赖冲突解决,达到使用目的?

 

 

二、解决问题

1、maven自动解决依赖冲突的规则是什么?

第一原则:路径最近者优先

项目A有如下的依赖关系:

A->B->C->X(1.0)

A->D->X(2.0)

则该例子中,X的版本是2.0

 

第二原则:路径相等,先声明者优先

项目A有如下的依赖关系:

A->B->Y(1.0)

A->C->Y(2.0)

若pom文件中B的依赖坐标先于C进行声明,则最终Y的版本为1.0

 

2、如何查看当前项目的maven依赖树?

复制代码

//进入项目的pom.xml文件的目录下,运行如下命令
//这个是正常依赖的树
mvn dependency:tree
//这个命令是查看maven是如何解决依赖冲突的依赖树
mvn -Dverbose dependency:tree
//如果想将依赖树打印到指定文件中,则命令如下
mvn -Dverbose  dependency:tree -Doutput=/Users/shangxiaofei/sxfoutput.txt

复制代码

3、如何从依赖树中找到自己预期的版本,是被那个jar给覆盖了?

例子:

 

递归依赖的关系列的算是比较清楚了,每行都是一个jar包,根据缩进可以看到依赖的关系。
最后写着compile的就是编译成功的。
最后写着omitted for duplicate的就是有jar包被重复依赖了,但是jar包的版本是一样的。
最后写着omitted for conflict with xxxx的,说明和别的jar包版本冲突了,而该行的jar包不会被引入。比如上面有一行最后写着omitted for conflict with 3.4.6,那么该行的zookeeper:jar:3.4.8不会被引入,会引入3.4.6版本

最后写着version managed from 2.3 ;omitted for duplicate ,表示最终使用commons-pool2最终会使用2.4.2,拒绝使用<dependencyManagement></dependencyManagement>中声明的2.3版本

最后写着version managed from 1.16.8 ;表示最终使用lombok:jar:1.16.22版本

 

4、如何人工进行依赖冲突解决,达到使用目的?

解决重复依赖和冲突的方法:

1,修改pom文件中两个dependency元素的位置。如果两个dependency都引用了一个jar包,但是版本不同,classloader只会加载jar包在pom文件中出现的第一个版本,以后出现的其他版本的jar包会被忽略。

不建议使用该方法,因为引用不同版本的jar包本身就是很危险的。

2,使用<exclusions>标签来去掉某个dependency依赖中的某一个jar包或一堆jar包,<exclusion>中的jar包或者依赖的相关jar包都会被忽略,从而在两个dependency都依赖某个jar包时,可以保证只使用其中的一个。

可以这么写:

复制代码

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>dubbo</artifactId>
    <version>2.8.3.2</version>
    <exclusions>
        <exclusion>
            <artifactId>guava</artifactId>
            <groupId>com.google.guava</groupId>
        </exclusion>
        <exclusion>
            <artifactId>spring</artifactId>
            <groupId>org.springframework</groupId>
        </exclusion>    
    </exclusions>
</dependency>

复制代码

 

 

====================Maven坐标基础知识===================

1、maven的依赖基础

复制代码

<dependency>    
<groupId>com.alibaba.share</groupId>    
<artifactId>test</artifactId>    
<version>1.4</version>    
</dependency>    
    
依赖库命名规则:    
${groupId.part1}/${groupId.part2}/${version}    
例:com/alibaba/share/1.4    
    
依赖库文件命名规则:    
${artifactId}-${version}-${classifier}.${type}    
例:test-1.4-source.jar    
    
注:classfier即分类器,多数的时候是用不到的,不过有写情况需要,例:    
TestNG强制需要你提供分类器,以区别jdk14和jdk15    
<dependency>      
   <groupId>org.testng</groupId>      
   <artifactId>testng</artifactId>      
   <version>5.7</version>      
   <classifier>jdk15</classifier>      
</dependency>    

复制代码

2、maven依赖范围 

<dependency>    
      <groupId>junit</groupId>    
      <artifactId>junit</artifactId>    
      <version>3.8.1</version>    
      <scope>test</scope>    
 </dependency> 

上面的scope即约定依赖范围。 
compile:默认值,一直可用,最后会被打包 
provided:编译期间可用,不会被传递依赖,不会被打包。例:依赖于web容器中的提供的一个jar包,在编译的时候需要加入依赖(web容器还没有介入),运行的时候由web容器来提供。 
test:执行单元测试时可用,不会被打包,不会被传递依赖 
runtime:运行和测试时需要,但编译时不需要 
system:不推荐使用 

 

3、maven依赖管理  

避免不同子模块中依赖版本冲突 
在父pom中配置依赖 

复制代码

<dependencyManagement>      
    <dependencies>      
     <dependency>      
       <groupId>mysql</groupId>      
       <artifactId>mysql-connector-java</artifactId>      
      <version>5.1.2</version>      
     </dependency>      
      ...      
   <dependencies>      
</dependencyManagement>    

复制代码

在子pom中添加依赖 

<dependencies>      
   <dependency>      
    <groupId>mysql</groupId>      
    <artifactId>mysql-connector-java</artifactId>      
   </dependency>      
</dependencies>    

dependencyManagement实际上不会真正引入任何依赖,在子pom中添加之后才会。在父pom中配置了之后,子模块只需使用简单groupId和artifactId就能自动继承相应的父模块依赖配置。如果子pom中定义了version,则覆盖management中的。 

 

4、可选依赖

<dependency>    
      <groupId>mysql</groupId>    
      <artifactId>mysql-connector-java</artifactId>    
      <version>1.5</version>    
      <optional>true</optional>    
    </dependency>   

5、依赖版本界限 

要求的依赖版本>=3.8且<4.0 

<version>[3.8,4.0)</version>   

要求的依赖版本<=3.8.1 

<version>[,3.8.1]</version>    

要求必须是3.8.1版本,如果不是的话会构建失败,提示版本冲突。原来的写法<version>3.8.1</version>的意思是所有版本都可以,但最好是3.8.1 

<version>[3.8.1]</version>   

 

6、排除依赖 

 依赖project-a但是排除掉对project-a中引入的project-b的依赖 

复制代码

<dependency>    
  <groupId>org.sonatype.mavenbook</groupId>    
  <artifactId>project-a</artifactId>    
  <version>1.0</version>    
  <exclusions>    
    <exclusion>    
      <groupId>org.sonatype.mavenbook</groupId>    
      <artifactId>project-b</artifactId>    
    </exclusion>    
  </exclusions>    
</dependency>    

复制代码

替换依赖 
直接使用上一步中的排除掉,然后添加要替换进来的依赖就可以了,没有什么特殊的标志来标志这个是替换进来的。 

 

7、版本冲突仲裁

版本仲裁规则(在maven 2.2.1版本上测试验证) 
• 按照项目总POM的DependencyManager版本声明进行仲裁(覆盖),但无警告。 
• 如无仲裁声明,则按照依赖最短路径确定版本。 
• 若相同路径,有严格区间限定的版本优先。 
• 若相同路径,无版本区间,则按照先入为主原则。 

 

 

<think>好的,用户想解决Maven依赖冲突的问题。首先,我需要回忆一下Maven处理依赖冲突的基本机制,比如最短路径优先和声明优先原则。根据引用内容,用户可能已经了解了一些基本方法,比如使用Maven Helper插件或者mvn dependency:tree命令。 用户的问题是如何定位和解决依赖冲突,所以需要分步骤说明。第一步应该是如何定位冲突,可能需要提到dependency:tree命令以及如何分析输出,引用[4]中提到了使用这个命令来追踪依赖路径。然后,定位到具体冲突后,如何解决呢?可能需要排除依赖或者统一版本,引用[3]和[4]都有提到排除依赖的方法,而引用[1]提到了Maven的默认策略。 接下来,解决部分需要具体的方法,比如手动排除、依赖管理统一版本,或者使用插件帮助。引用[2]和[5]提到了Maven Helper插件,可以可视化分析,这部分应该详细说明操作步骤。另外,可能还需要提到手动检查pom文件,或者使用dependencyManagement来锁定版本,如引用[3]中的例子。 还要注意用户可能需要具体的示例,比如如何在pom.xml中写排除语句,或者如何用dependencyManagement控制版本。需要确保给出的步骤清晰,并且参考了提供的引用资料,比如引用[4]中的例子展示了如何排除依赖,引用[5]提到了Dependency Analyzer按钮。 最后,生成相关问题的时候,要围绕Maven依赖冲突的扩展问题,比如原理、插件推荐、项目依赖过多时的处理,以及如何强制使用特定版本。这些都需要基于已有的引用内容来组织,确保问题相关且有依据。 需要检查是否所有步骤都覆盖了定位和解决,并且每个步骤都有对应的引用支持。另外,语言要符合中文,使用正确的LaTeX格式,比如命令用$符号包裹。同时,回答结构要清晰,分点说明,帮助用户一步步解决问题。</think>### 如何定位和解决Maven项目中的依赖冲突 #### 一、定位依赖冲突 1. **使用`mvn dependency:tree`命令** 在项目根目录执行以下命令生成依赖树,观察冲突版本: ```bash mvn dependency:tree -Dverbose -Dincludes=groupId:artifactId ``` 通过`-Dincludes`过滤特定依赖,例如`-Dincludes=com.squareup.okhttp3:*`,输出结果会显示依赖路径和版本冲突的位置[^4]。 2. **使用Maven Helper插件** 在IntelliJ IDEA中安装插件后: - 打开`pom.xml`,点击底部【Dependency Analyzer】 - 在“Conflicts”选项卡中直接查看红色标记的冲突依赖[^2][^5]。 3. **运行时异常分析** 若出现`NoSuchMethodError`或`ClassNotFoundException`,根据堆栈信息定位缺失类或方法,反推冲突的依赖版本。 --- #### 二、解决依赖冲突 1. **手动排除依赖(Exclusion)** 在`pom.xml`中显式排除冲突版本: ```xml <dependency> <groupId>com.example</groupId> <artifactId>library</artifactId> <version>1.0.0</version> <exclusions> <exclusion> <groupId>com.conflict</groupId> <artifactId>conflict-artifact</artifactId> </exclusion> </exclusions> </dependency> ``` 此方法适用于明确知道冲突来源的场景[^3]。 2. **统一版本(Dependency Management)** 在父`pom.xml`的`<dependencyManagement>`中强制指定版本: ```xml <dependencyManagement> <dependencies> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>32.1.3-jre</version> </dependency> </dependencies> </dependencyManagement> ``` Maven会优先使用此处定义的版本[^1]。 3. **调整依赖声明顺序** Maven遵循“最短路径优先”和“声明优先”原则。若两个依赖路径长度相同,则按`pom.xml`中声明的顺序选择第一个版本[^1]。 --- #### 三、验证解决效果 1. 重新执行`mvn dependency:tree`确认冲突消失。 2. 运行单元测试或启动项目,验证相关功能是否恢复正常。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值