当前位置: 首页 > news >正文

maven冲突管理及依赖管理实践

1、“最近获胜策略(nearest wins strategy)”的方式处理依赖冲突

Maven采用“最近获胜策略(nearest wins strategy)”的方式处理依赖冲突,即如果一个项目最终依赖于相同artifact的多个版本,在依赖树中离项目最近的那个版本将被使用。让我们来看看一个实际的例子。

我们有一个web应用resolve-web,该工程依赖于project-A和project-B,project-A依赖于project-common的1.0版本并调用其中的sayHello()方法。project-B依赖于project-C,而project-C又进一步依赖于project-common的2.0版本并调用其中的sayGoodBye()方法。project-common的1.0和2.0版本是不同的,1.0中之包含sayHello()方法,而2.0中包含了sayHello()和sayGoodBye()两个方法。整个项目的依赖关系如下图:

 

根据Maven的transitive依赖机制,resolve-web将同时依赖于project-common的1.0和2.0版本,这就造成了依赖冲突。而根据最近获胜策略,Maven将选择project-common的1.0版本作为最终的依赖。这和Gradle不同,Gradle在默认情况下将选择最新的版本作为获胜版本。而对于Maven,由于proejct-common的1.0版本比2.0版本在依赖树中离resolve-web更近,故1.0版本获胜。project-common:project-commmon:jar:2.0被忽略掉了。此时在resolve-web的war包中将只包含project-common的1.0版本,于是问题来了。由于project-common的1.0版本中不包含sayGoodBye()方法,而该方法正是project-C所需要的,所以运行时将出现“NoSuchMethodError”。

2、依赖冲突的解决方法

方法1:在最近pom文件中显式加入依赖。先前的2.0版本不是离resolve-web远了点吗,那我们就直接将它作为resolve-web的依赖,这不就比1.0版本离resolve-web还近吗?在resove-web的pom.xml文件中直接加上对project-common 2.0 的依赖
方法2:在pom文件中引入依赖时排除多冲突jar包的依赖,如在resolve-web对project-A的dependency声明中,将project-common排除掉。

3、Maven的默认插件

Maven就其本身来说只是提供一个执行环境,它并不知道需要在项目上完成什么操作,真正操作项目的是插件(plugin),比如编译Java有Compiler插件,打包有Jar插件等。所以要让Maven完成各种各样的任务,我们需要配置不同的插件,甚至自己编写插件。你可能要问了:“我并没有配置什么插件啊,照样能编译打包。”这是因为Maven在默认情况下已经给我们配置了一些常用的插件,上面的Compiler和Jar便在这些插件之列。要查看Maven的默认插件,我们需要找到Super Pom。就像Java中的类隐式继承Object一样,对于pom.xml来说,它隐式继承超级POM。针对Maven3来说,该超级POM位于maven-model-builder-VERSION.jar包中(该jar包位于maven根目录/lib下)

解压该jar包,可以在maven-model-builder-VERSION/org/apache/maven/model目录中找到pom-4.0.0.xml,即超级POM。

4、依赖范围

主要的依赖范围以及作用:

 

依赖范围(scope)主源码classpath可用测试源码classpath可用会被打包
compile 缺省值TRUETRUETRUE
testFALSETRUEFALSE
runtimeFALSETRUETRUE
providedTRUETRUEFALSE

5、分类器

GAV是Maven坐标最基本最重要的组成部分,但GAV不是全部。还有一个元素叫做分类器(classifier),90%的情况你不会用到它,但有些时候,分类器非常不可或缺。

举个简单的例子,当我们需要依赖TestNG的时候,简单的声明GAV会出错,因为TestNG强制需要你提供分类器,以区别jdk14和jdk15,我们需要这样声明对TestNG的依赖:

Xml代码   收藏代码
  1. <dependency>  
  2.   <groupId>org.testng</groupId>  
  3.   <artifactId>testng</artifactId>  
  4.   <version>5.7</version>  
  5.   <classifier>jdk15</classifier>  
  6. </dependency>  

你会注意到maven下载了一个名为testng-5.7-jdk15.jar的文件。其命名模式实际上是<artifactId>-<version>-<classifier>.<packaging>。理解了这个模式以后,你就会发现很多文件其实都是默认构件的分类器扩展,如 myapp-1.0-test.jar, myapp-1.0-sources.jar。

分类器还有一个非常有用的用途是:我们可以用它来声明对test构件的依赖,比如,我们在一个核心模块的src/test/java中声明了一些基础类,然后我们发现这些测试基础类对于很多其它模块的测试类都有用。没有分类器,我们是没有办法去依赖src/test/java中的内容的,因为这些内容不会被打包到主构件中,它们单独的被打包成一个模式为<artifactId>-<version>-test.jar的文件。

我们可以使用分类器来依赖这样的test构件:

Xml代码   收藏代码
  1. <dependency>  
  2.   <groupId>org.myorg.myapp</groupId>  
  3.   <artifactId>core</artifactId>  
  4.   <version>${project.version}</version>  
  5.   <classifier>test</classifier>  
  6. </dependency>  

理解了分类器,那么可供依赖的资源就变得更加丰富。

6、多模块依赖管理

当你只有一个Maven模块的时候,你完全不需要看这个部分。但你心里应该清楚,只有一个Maven模块的项目基本上只是个玩具。

实际的项目中,你会有一大把的Maven模块,而且你往往发现这些模块有很多依赖是完全项目的,A模块有个对spring的依赖,B模块也有,它们的依赖配置一模一样,同样的groupId, artifactId, version,或者还有exclusions, classifer。细心的分会发现这是一种重复,重复就意味着潜在的问题,Maven提供的dependencyManagement就是用来消除这种重复的。

正确的做法是:

1. 在父模块中使用dependencyManagement配置依赖

2. 在子模块中使用dependencies添加依赖

dependencyManagement实际上不会真正引入任何依赖,dependencies才会。但是,当父模块中配置了某个依赖之后,子模块只需使用简单groupId和artifactId就能自动继承相应的父模块依赖配置。

Maven提高篇系列之(五)——处理依赖冲突 - 无知者云 - 博客园

Maven最佳实践:管理依赖

相关文章:

  • 每日学习记录5.10
  • SQL Server--系统监视与性能调整
  • CWnd类
  • jquery select操作
  • docker学习二 安装docker
  • OSPF协议的详解(一)
  • Network----轮询
  • 试用win7的70个技巧
  • 逃离方法牢笼
  • 并发连接MySQL
  • 移动BPM在何处?
  • Java-文件File简单实用
  • 二叉树表达规定形式的代数表达式并计算表达式结果
  • 13、openssl、ssh、脚本信息捕获 学习笔记
  • C#中的编译时的类型与运行时的类型
  • 「前端早读君006」移动开发必备:那些玩转H5的小技巧
  • 10个最佳ES6特性 ES7与ES8的特性
  • 2018一半小结一波
  • 4. 路由到控制器 - Laravel从零开始教程
  • Android组件 - 收藏集 - 掘金
  • angular2开源库收集
  • CSS实用技巧干货
  • Hibernate【inverse和cascade属性】知识要点
  • iOS帅气加载动画、通知视图、红包助手、引导页、导航栏、朋友圈、小游戏等效果源码...
  • JavaScript-Array类型
  • Netty+SpringBoot+FastDFS+Html5实现聊天App(六)
  • Python打包系统简单入门
  • V4L2视频输入框架概述
  • vuex 笔记整理
  • 搞机器学习要哪些技能
  • 关键词挖掘技术哪家强(一)基于node.js技术开发一个关键字查询工具
  • 基于游标的分页接口实现
  • 前端路由实现-history
  • 前端学习笔记之观察者模式
  • 收藏好这篇,别再只说“数据劫持”了
  • 手机端车牌号码键盘的vue组件
  • 算法-插入排序
  • 通过git安装npm私有模块
  • 微信小程序实战练习(仿五洲到家微信版)
  • 我是如何设计 Upload 上传组件的
  •  一套莫尔斯电报听写、翻译系统
  • 用jquery写贪吃蛇
  • ​香农与信息论三大定律
  • #QT(智能家居界面-界面切换)
  • #我与Java虚拟机的故事#连载16:打开Java世界大门的钥匙
  • (待修改)PyG安装步骤
  • (附源码)计算机毕业设计SSM疫情下的学生出入管理系统
  • (六)c52学习之旅-独立按键
  • (三)终结任务
  • (十二)springboot实战——SSE服务推送事件案例实现
  • (转)平衡树
  • .NET 8 中引入新的 IHostedLifecycleService 接口 实现定时任务
  • .NET Core Web APi类库如何内嵌运行?
  • .Net 中的反射(动态创建类型实例) - Part.4(转自http://www.tracefact.net/CLR-and-Framework/Reflection-Part4.aspx)...
  • .net 重复调用webservice_Java RMI 远程调用详解,优劣势说明