用dependency:tree查看maven引入jar包的传递依赖

maven项目的pom.xml文件给项目导入了不一样的jar包,有时候不一样的dependency会引入同一个jar包的不一样版本。spring

当不一样版本的jar包被依赖后,可能会出现:apache

  1. 冲突。
  2. 有的版本的jar包不会被classloader引入,而有的代码确实须要那个没有被引入的jar包,进而出现错误。

在pom.xml文件的目录下使用mvn dependency:tree命令能够查看jar包的传递依赖。api

使用-Dverbose 参数能够列出更详细的信息。tomcat

mvn -Dverbose dependency:treebash

从命令运行的输出内容来看,该命令执行的时候会从新build一次。eclipse

若是节选输出内容的其中一部分,多是这样的:jsp

[INFO] +- org.apache.tomcat:tomcat-servlet-api:jar:7.0.70:compile
[INFO] +- org.apache.tomcat:tomcat-jsp-api:jar:7.0.70:compile
[INFO] |  +- org.apache.tomcat:tomcat-el-api:jar:7.0.70:compile
[INFO] |  \- (org.apache.tomcat:tomcat-servlet-api:jar:7.0.70:compile - omitted for duplicate)
[INFO] +- net.sf.jasperreports:jasperreports:jar:5.6.0:compile
[INFO] |  +- (commons-beanutils:commons-beanutils:jar:1.8.0:compile - omitted for conflict with 1.8.3)
[INFO] |  +- commons-collections:commons-collections:jar:3.2.1:compile
[INFO] |  +- commons-digester:commons-digester:jar:2.1:compile
[INFO] |  |  +- (commons-beanutils:commons-beanutils:jar:1.8.3:compile - omitted for duplicate)
[INFO] |  |  \- (commons-logging:commons-logging:jar:1.1.1:compile - omitted for duplicate)

递归依赖的关系列的算是比较清楚了,每行都是一个jar包,根据缩进能够看到依赖的关系。maven

  • 最后写着compile的就是编译成功的。
  • 最后写着omitted for duplicate的就是有jar包被重复依赖了,可是jar包的版本是同样的。
  • 最后写着omitted for conflict with xxxx的,说明和别的jar包版本冲突了,而该行的jar包不会被引入。好比上面有一行最后写着omitted for conflict with 1.8.3,那么该行的commons-beanutils:jar:1.8.0不会被引入,只有1.8.3版本的会被引入。

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

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>

 

对于Jar包冲突问题,咱们开发人员常常都会有碰到,当咱们使用一些jar包中的类、方法等,或者有时遇到一些日志系统的问题(参考另外一篇文章Jar包冲突致使的日志问题),咱们会遇到ClassNotFoundException,NoSuchFieldException,NoSuchMethodException 之类的运行时异常,从经验上咱们就会判断,Jar包冲突了。解决Jar包冲突问题,每一个人都有每一个人的方法,这里我介绍一下个人方法,供你们参考。

处理方法

当遇到jar包冲突时,咱们首先肯定是哪一个jar包冲突了,这个很容易,看咱们调用的类或方法,是属于哪一个Jar包。而后就是要找出冲突了,我这里使用命令

mvn dependency:tree -Dverbose -Dincludes=<groupId>:<artifactId>

填写上Jar包的groupId和artifactId,能够只有一个,可是中间的冒号不要少,这样就会输出依赖树,并且是仅包含这个Jar包的依赖树,这样那些地方依赖了这个Jar包的那个版本就一目了然了。
例如,个人项目中notify-common包存在冲突,咱们使用命令

mvn dependency:tree -Dverbose -Dincludes=:notify-common

获得依赖树输出

[INFO] com.taobao.wlb:bis-server:war:1.0-SNAPSHOT
[INFO] +- com.taobao.wlb:bis-core:jar:1.0-SNAPSHOT:compile
[INFO] |  \- com.taobao.logistics:schedule-client:jar:1.1.1:compile
[INFO] |     \- (com.taobao.notify:notify-common:jar:1.8.15:compile - omitted for conflict with 1.8.19.26)
[INFO] \- com.taobao.notify:notify-tr-client:jar:1.8.19.26:compile
[INFO]    +- com.taobao.notify:notify-common:jar:1.8.19.26:compile
[INFO]    \- com.taobao.notify:notify-remoting:jar:1.8.19.26:compile
[INFO]       \- (com.taobao.notify:notify-common:jar:1.8.19.26:compile - omitted for duplicate)

看一下依赖树中全部的叶子节点就是全部的notify-common包,咱们能够看到咱们依赖的bis-core中依赖了schedule-client包,它依赖了一个notify-common包,版本是1.8.15,第四行的后面也提示了这个包同其余包有冲突- omitted for conflict with 1.8.19.26)。而咱们的系统依赖的notify-tr-client包所依赖的版本是1.8.19.26,因而咱们知道是这里冲突了,在POM排除掉依赖,OK了。

说明

这里咱们对咱们执行的命令作一个简单的说明。

mvn dependency:tree -Dverbose -Dincludes=<groupId>:<artifactId>

第一部分mvn dependency:tree是maven依赖的分析命令,做用是对咱们的项目的依赖进行分析,并输出项目依赖树
第二部分-Dverbose的做用是添加了verbose一个环境变量,起的做用是在分析项目依赖时输出明细,这样项目中依赖的全部引用都会被输出出来,包含了全部的间接引用,会有不少不少,咱们只须要咱们要找的,因此就须要第三个参数了

第三部分-Dincludes=<groupId>:<artifactId>的做用就是进行过滤,只包含咱们想要的依赖的依赖时,排除掉其它不须要的,依赖树的全部叶子节点就是咱们的找的依赖包。其中的groupId和artifactId能够只填写一个,为了保证准确性,通常都会填两个(填写时不包括尖括号)。

其余方法:

一、对于maven工程,个人办法是使用eclipse来解决,点开pom.xml,切换到hierarchy dependency,右上角搜索对应的包,能够清晰地看到冲突版本

二、可使用idea,在pom.xml中右单击 选择Diagrams-》show dependencies

三、mvn dependency:tree -Dverbose > tree.log 
直接输出冲突的jar文件

Maven依赖

1. 依赖的配置

    根元素project下的dependencies能够包含一个或多个dependency元素,以声明一个或多个依赖。每一个依赖能够包含的元素有:
groupId、artifactId和version:依赖的基本坐标,坐标三元素。
type:依赖的类型,对应于项目定义的packaging,大部分状况下不须要定义,使用默认值jar。
scope:依赖的范围。
optional:标记依赖是否可选。
exclusions:用来排除传递性依赖。

2. 依赖的范围

依赖范围(scope) 对于编译classpath有效 对于测试classpath有效 对于运行时classpath有效
编译依赖范围:compile Y Y Y
测试依赖范围:test - Y -
已提供依赖范围:provided Y Y -
运行时依赖范围:runtime - Y Y
系统依赖范围:system Y Y -

另外还有导入依赖范围:import,该范围不会对三种classpath产生实际的影响。

3. 传递性依赖,和数学里的传递性,是一样的概念。

    当A有一个compile范围的B依赖,B有一个compile范围的C依赖,那么C就会成为A的compile范围依赖,C是A的一个传递性依赖。
    有了传递性依赖的机制,在使用某个依赖时就不须要考虑它依赖了什么,也不须要担忧引入多余的依赖。Maven会解析各个直接依赖的POM,将那些必要的间接依赖,以传递性依赖的形式引入到当前的项目中。
    须要注意的是,可选依赖不会被传递。

4. 依赖范围影响传递性依赖

  compile test provided runtime
compile compile - - runtime
test test - - test
provided provided - provided provided
runtime runtime - - runtime

5. 依赖调解

 当两个依赖路径上有两个版本的依赖X时,有如下两个依赖调解原则:
第一原则:路径最近者优先;
第二原则:路径长度同样时,第一声明者优先。

6. 排除依赖

当项目A依赖于项目B,可是不想引入传递性依赖C,而是本身显示的声明对项目C另外一个版本的依赖,使用exclusions元素声明排除性依赖。

    exclusions能够包含一个或者多个exclusion子元素,声明exclusion时只须要groupId和artifactId,不须要version元素。

7. 归类依赖

当项目中依赖了同一项目的不一样模块,它们的版本都是相同的,所以在升级的时候,这些依赖的版本会一块儿升级。为了不重复,且须要修改时只修改一处,能够经过归类依赖来解决。

    使用properties元素定义Maven属性,如springframework.version子元素,并定义其值。有了这个属性定义,maven运行时会将POM中全部的${springframwork.version}替换成定义的实际值。

8. 优化依赖

使用dependency:list和dependency:tree 帮助咱们详细了解项目中全部依赖的具体信息。

使用dependency:analyze工具能够帮助分析当前项目的依赖。

analyze的结果中包含了两部分:

Used undeclared dependencies:项目中使用但未显式声明的依赖。这种依赖意味着潜在的风险;

Unused declared dependencise:项目中未使用的,但显式声明的依赖。对于这种依赖不能直接删除,由于analyze只会分析编译和测试须要的依赖,其余依赖它没法发现,所以须要仔细分析。

相关文章
相关标签/搜索