今天给大家分享一下,修真院官网JAVA任务7中的深度思考,怎么处理maven依赖冲突?
一、背景介绍
我查看的讲依赖冲突的教程中提到,依赖冲突常见的错误是出现很多奇怪的错误,如果有一定的开发经验了,当出现奇怪报错时就需要考虑依赖冲突了。还有一点,依赖冲突的解决在多模块的大型项目中很重要,但是单model的项目,中基本maven自己就解决了。所以初学者不要过多关注,就是以后工作了,这些事情也不会交给新手的,况且许多公司的框架可能都是多年不变的,更不可能让你动了。
maven的依赖冲突是怎么产生的?
依赖冲突自然是项目中依赖的jar包出现冲突了,具体体现为相同的groupId和artifactId,但是出现了不同的version,所以才会出现冲突。而产生冲突的原因是依赖传递引起的。我们都知道,做项目时需要引入各种各样的依赖,而这些依赖本身也是一些项目,所以它们本身也需要依赖其他jar包。所以在maven做项目管理时,maven自动将这些jar包所依赖的jar查询并导入进来了。这就势必导入一些版本冲突的jar包。
二.知识剖析
对此maven有自己的策略来解决依赖冲突,而处理冲突的功能是“依赖仲裁(dependency mediation)”。在maven2.0的版本中采用了策略“nearest wins”。这是什么呢?这又涉及到新的概念,层、深度或路径。这三个的解释差不多,都是用来描述依赖所处的位置。先看下下面的部分文档:
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ java-task7 ---
[INFO] com.ptteng:java-task7:war:1.0-SNAPSHOT
[INFO] +- org.slf4j:slf4j-api:jar:1.7.12:compile
[INFO] +- org.slf4j:slf4j-log4j12:jar:1.7.12:compile
[INFO] | \- (org.slf4j:slf4j-api:jar:1.7.12:compile - omitted for duplicate)
[INFO] +- org.apache.tiles:tiles-extras:jar:3.0.5:compile
[INFO] | +- org.apache.tiles:tiles-core:jar:3.0.5:compile
[INFO] | | +- org.apache.tiles:tiles-api:jar:3.0.5:compile
[INFO] | | | \- (org.slf4j:slf4j-api:jar:1.7.6:compile - omitted for conflict with 1.7.12)
[INFO] | | +- org.slf4j:jcl-over-slf4j:jar:1.7.21:compile
这是我用maven命令‘mvn dependency:tree’导出的项目依赖树。同时这个命令添加了参数‘-Dverbose’,所以内容比较多。从这一段就可以看出层、深度或路径的概念。尤其是这句“org.slf4j:slf4j-api:jar:1.7.6:compile - omitted for conflict with 1.7.12“就是maven自动采用“nearest win”的策略,用1.7.12的版本代替了1.7.6的版本,从而解决了多个org.slf4j:slf4j-api:jar版本冲突的问题。因为在项目中声明了org.slf4j:slf4j-api:jar:1.7.12,所以这就属于最浅的层了。
但是如果遇到相同层的怎么办?直到maven2.0.9才提出了”by order"的策略,就是声明的前后顺序,在前的赢。
处理maven自动处理依赖冲突,还可以项目开发者控制。maven提供的功能是:dependency management,dependency scope,excluded dependencies,optional dependencies。这些功能在pom.xml文件中都有对应标签提供了这些功能。分别是<dependencyManagement>(放置<dependencies>外面),<scope>(在groupId的同级),<exclusions><exclusion></exclusion></exclusions>(也是和groupId同级的,里面填写不包含的groupId,artifactId),<optional>。
其中scope的值有compile(默认值),provided,runtime,test,system,import。每个用处就是限定了该依赖jar包的使用范围,并决定依赖是否传递到其他层。具体差别可以参考maven官网讲依赖传递机制的内容。里面也提供了一些pom.xml文件的例子。
接下来讲下查看依赖冲突的方式,首先是maven的命令行查看依赖树,就是前面提到的命令“mvn dependency:tree”,需要的参数有“-Dverbose”,可以自己对比下输出的信息全面程度。这时信息很多,查看起来不方便,需要另外一个参数”-Dincludes=groupId:artifactId“可以查看指定jar包的依赖冲突,这时查看就比较方便了。同时还可以导出到本地文件。在命令的最后添加“ > filepath/filename.filetype”这样就输出到指定文件了,不写文件路径,默认导出到项目的根目录。
intellij idea中也可以查看,右键maven -》show dependencies,或者是在maven的tool button中选择那个树形的图标可以直接打开,依赖依赖树窗口。在里面可以使用ctrl+f搜索指定jar包,确定后会出现好多红色虚线,上面写着冲突的版本号。之后右键选择exclude或是在pom.xml中添加exclusions元素,具体怎么写自己多试试,我的效果不太好就不说了。
到了这时还是会小概率的出现些漏网之鱼。我看有个教程写了个方法,感兴趣的可以学习下。
三、常见问题
1、什么是依赖冲突?
2、maven解决依赖冲突的机制?
3、依赖范围有哪些?
四.解决方案
1、答:依赖冲突是由依赖传递引起的版本冲突。项目中的依赖都有自身的依赖,这些依赖会传递到当前项目中。然后根据依赖版本的不同,就导致了依赖冲突。
2、答:maven有两种自动的解决依赖冲突的机制:最短路径和by order优先。前者是产生依赖冲突的依赖采用离项目最近(就是路径最短的)的那个版本。后者是指相同路径深度时,采用最先声明的那个版本。
还有手动控制的禁止依赖传递和取消依赖的方法。
3、答:compile,provided,runtime,test,system,import。
五。编码实战
六、参考文献
http://www.cnblogs.com/davenkin/p/advanced-maven-resolve-dependencies-conflicts.html
https://www.cnblogs.com/chowmin/articles/3891199.html
https://github.com/davenkin/maven-dependency-conflict-demo
http://ian.wang/106.htm
8.更多讨论
鸣谢
感谢观看,如有出错,恳请指正
七.更多讨论
详见视频
感谢大家观看
今天的分享就到这里啦,欢迎大家点赞、转发、留言、拍砖~
我的邀请码链接:http://www.jnshu.com/login/1/20535344
使用我的优惠码优惠多多!
我的邀请码:20535344
技能树.IT修真院
“我们相信人人都可以成为一个工程师,现在开始,找个师兄,带你入门,掌控自己学习的节奏,学习的路上不再迷茫”。
这里是技能树.IT修真院,成千上万的师兄在这里找到了自己的学习路线,学习透明化,成长可见化,师兄1对1免费指导。快来与我一起学习吧~