添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
  • 有的版本的jar包不会被classloader引入,而有的代码确实需要那个没有被引入的jar包,进而出现错误。
  • 在pom.xml文件的目录下使用 mvn dependency:tree 命令可以查看jar包的传递依赖。

    使用-Dverbose 参数可以列出更详细的信息。

    mvn -Dverbose dependency:tree

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

    如果节选输出内容的其中一部分,可能是这样的:

    [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包,根据缩进可以看到依赖的关系。

  • 最后写着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版本的会被引入。
  • 解决重复依赖和冲突的方法:

    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可以只填写一个,为了保证准确性,一般都会填两个(填写时不包括尖括号)。

    其他方法:

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

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

    3、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 测试依赖范围:test 已提供依赖范围:provided 运行时依赖范围:runtime 系统依赖范围:system

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

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

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

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

    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只会分析编译和测试需要的依赖,其他依赖它无法发现,因此需要仔细分析。