依赖冲突产生的原因:
- 如果项目的依赖A和依赖B同时引入了依赖C。
- 如果依赖C在A和B中的版本不一致就可能依赖冲突。
- 比如 项目 <- A, B, A <- C(
1.0
),B <- C(1.1
)。 - 那么maven如果选择高版本C(
1.1
)来导入(这个选择maven会根据不等路径短路径原则和同等路径第一声明原则选取),C(1.0
)中的类c在C(1.1
)中被修改而不存在了。 - 在编译期可能并不会报错,因为编译的目的只是把业务源代码编译成class文件,所以如果项目源代码中没有引入共有依赖C因升级而缺失的类c,就不会出现编译失败。除非源代码就引入了共有依赖C因升级而缺失的类c则会直接编译失败。
- 在运行期,很有可能出现依赖A在执行过程中调用C(
1.0
)以前有但是升级到C(1.1
)就缺失的类c,导致运行期失败,出现很典型的依赖冲突时的NoClassDefFoundError
错误。 - 如果是升级后出现原有的方法被修改而不存在的情况时,就会抛出
NoSuchMethodError
错误。
传递依赖
maven坐标有一项scope此元素指的是任务的类路径(编译和运行时,测试等)以及如何限制依赖关系的传递性。
有 6 种可用的限定范围:
compile 编译依赖范围 如果没有指定 scope 标签,maven 默认为这个范围。
test 测试依赖范围 正常使用应用程序不需要依赖关系 Junit
provided 已提供依赖范围 它只适用于编译和测试 servlet-api
runtime 运行时依赖范围 此范围表示编译不需要依赖关系,而是用于执行 jdbc驱动
system和 provided 依赖范围一致,需要通过 <systemPath> 显示指定,且可以引用环境变量
import 导入依赖范围。使用该选项,通常需要 <type>pom</type>,将目标 pom 的 dependencyManagement 配置导入合并到当前 pom 的 dependencyManagement 元素。
依赖传递性以及依赖范围
何为传递性依赖
依赖范围与传递性依赖的关系
依赖冲突解决方案
1、maven本身处理机制-依赖调解
短路径优先:假如有以下依赖:A -> B -> C ->X(版本 1.0) 和 A -> D -> X(版本 2.0),则优先解析较短路径的 X(版本 2.0);
先声明优先:若路径长度相同,则谁先声明,谁被解析。
2、可选依赖
optional可选依赖
A->B、B->X(可选),B->Y(可选) X,Y依赖不会传递到A中
可选依赖用于两个特性相互互斥,例如 mysql,PostgreSQL不能同时实现特性
3、排除依赖
exclusions元素声明排除依赖
4、归类依赖-版本锁定
利用properties统一声明版本,涉及到相同系列包,修改${properties}即可统一替换
优化依赖
1、查看已解析的依赖
mvn dependency:list
一层为顶层依赖,顶层依赖的依赖为二级依赖,以此类推
2、查看依赖树
mvn dependency:tree
通过上方的命令解析之后会构成依赖树,利用依赖树可以清楚看到依赖引入的传递路径
3、分析项目当前依赖
mvn dependency:analyze
Used undeclared dependencies found
这个是指某些依赖的包在代码中有用到它的代码,但是它并不是直接的依赖(就是说没有在pom中直接声明),是通过引入传递下来的包
Unused declared dependencies found
这个是指我们在pom中声明了依赖,但是在实际代码中并没有用到这个包!也就是多余的包。 这个时候我们就可以把这个依赖从pom中剔除
注意:这里说的实际代码没有用到,指的是在main/java和test里没有用的,但是并不是意味着真的没有用到这些包,有可能配置文件中引用或者其他扩展点自动加载这些包,所以我们在删除依赖的时候一定要小心,做好备份,因为这类引用maven是分析不出来的。
常用命令
修改版本号命令
安装插件
mvn vsersion:set -DnewVersion=1.1-SANPSHOT
激活环境
mvn clean package -P dev
跳过单元测试
-Dmaven.test.skip=true