冲突1
项目Demo1依赖于Y、Z依赖包,Y依赖于A,Z依赖于A、B、C,故项目Demo1最终依赖于Y、Z、A、B、C。但是Y依赖于A的1.x版本,Z依赖于A的2.x版本,这时候就出现依赖包冲突。
世界原是美好的。存在有些依赖包,版本更新的改动小,不会影响使用,即加载哪个版本的依赖包都不影响项目。像log4j日志系列某一批版本畅通无阻,当然不同日志系列一起引用仍有可能存在问题(比如log4j和logback一起,虽然是同一个创始人)
if(A的2.x向下兼容1.x) 只需要保留2.x版本,exclude掉Y依赖的A的版本。
else
1. 寻找Y或者Z可替换的依赖包,直到不冲突
2. 如没有替换依赖包,估计悲剧了。要不修改Y、Z依赖包源码(有提供源码的基础上),要不自己重现实现。
<!--exclude掉Y依赖的A的版本-->
<dependency>
<groupId>a.b.c</groupId>
<artifactId>Y</artifactId>
<version>${Y.version}</version>
<exclusions>
<exclusion>
<artifactId>aa.bb.cc</artifactId>
<groupId>A</groupId>
</exclusion>
</exclusions>
</dependency>
话说,如何有效确认哪些包有冲突?
您需要一个层级树的展示方式。
普通版
主流的IDE已经集成了maven命令,所以层级树的展示不是问题。比如eclipse:
bigger版
总有那么一些牛x的人,不喜欢用IDE集成开发平台,追求原生态。
他们喜欢直接操作maven命令:mvn dependency:tree
冲突2
SDK是部门业务的基础的依赖包,对接部门主要业务底层,故主要服务都依赖于SDK依赖包。SDK依赖于几十个依赖包,服务S1、S2、S3依赖于SDK,同时依赖于其他依赖包A、B、C…X、Y、Z等。
依赖包多不是问题,问题是其他的依赖包和SDK依赖包有不少交集,有不少交集也不是问题,反正maven会管理,问题是不少交集中有好几个包版本冲突,冲突也不是问题,你还不兼容。。。。。。(好吧,让服务S1、S2、S3负责人改用高版本依赖包,谁让他们用那么老的版本。负责人:TMD,!@¥#……&@!@,这项目是上上上代流传下来的。)
世界原是美好的。印象中,似乎好像也许,maven支持多模块项目的建立。有点意思,虽然不完全符合我们需要的,但是够了。我不需要maven的多模块机制,只需要父模块可以抽取公用的依赖包、插件、maven库、变量属性这个特性。
上述问题是个表面现象。其实部门的项目开发都是多个项目组同时进行,即使可以保证每个项目组组内使用依赖包版本一致,也保证不了整个部门,整个公司。
利用父模块的特性,打算提取一个超级父模块,里面抽取了公用插件、公用maven库、变量属性(项目组或部门或公司所有依赖包版本号,这是个积累的过程,属性名约定俗成为${artifactId}.version。在子模块引用依赖的时候,如果无法引入,那么就是这个依赖包版本不存在父模块,可添加。注意:可能存在artifactId一致,groupid不一样的依赖包,此时需特殊处理),如下父模块pom.xml
<groupId>x.y.z</groupId>
<artifactId>project-base</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<name>project-base</name>
<url>http://maven.apache.org</url>
<properties>
<!-- 编译时的编码 -->
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
<!-- 文件拷贝时的编码 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- 依赖包版本 -->
<aspectjweaver.version>1.8.6</aspectjweaver.version>
<aspectjrt.version>1.8.6</aspectjrt.version>
<commons-beanutils.version>1.9.2</commons-beanutils.version><!-- <groupId>commons-beanutils</groupId> -->
<commons-codec.version>1.10</commons-codec.version><!-- <artifactId>commons-codec</artifactId> -->
<commons-lang3.version>3.4</commons-lang3.version><!-- <groupId>org.apache.commons</groupId> -->
<commons-io.version>2.4</commons-io.version><!-- <groupId>commons-io</groupId> -->
<gson.version>2.3.1</gson.version><!-- <groupId>com.google.code.gson</groupId> -->
<guava.version>18.0</guava.version><!-- <groupId>com.google.guava</groupId> -->
<joda-time.version>2.8.2</joda-time.version><!-- <groupId>joda-time</groupId> -->
<junit.version>4.12</junit.version><!-- <groupId>junit</groupId> -->
<log4j.version>1.2.17</log4j.version><!-- <groupId>log4j</groupId> -->
<spring.version>4.2.0.RELEASE</spring.version><!-- <groupId>org.springframework</groupId> -->
<properties>
<repositories>
<repository>
...
</repository>
</repositories>
<build>
<plugins>
<plugin>
...
</plugin>
</plugins>
</build>
子模块pom.xml
<parent>
<artifactId>project-base</artifactId>
<groupId>x.y.z</groupId>
<version>1.0</version>
</parent>
<groupId>x.y.z.a</groupId>
<artifactId>S1</artifactId>
<version>1.0.1</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>
</dependencies>
总结
个人遇到依赖包冲突,一般出现如下几个情景:
- 服务启动偶尔报错,偶尔正常(加载顺序导致)
- NoClassDefFoundErro