maven依赖及冲突解决

1 Maven 依赖POM配置

		<project>
		    ...
		    <dependencies>
		        <dependency>
		            <groupId>...</groupId>
		            <artifactId>...</artifactId>
		            <version>...</version>
		            <type>...</type>
		            <scope>...</scope>
		            <optional>...</optional>
		            <exclusions>
		                <exclusion>
		                    ...
		                </exclusion>
		                ...
		            </exclusions>
		        </dependency>
		        ...
		    </dependencies>
		    ...
		</project>

         其中,groupId、artifactId 和 version 是 Maven 依赖的基本坐标,也是最重要的。其他的元素如 type 表示依赖的类型,默认为jar;scope 为依赖的范围,默认为compile;optional 用来标记依赖是否可选;exclusions 用来排除传递性依赖。

2 依赖范围

         依赖范围,正是其中 scope 元素所能选择的内容。在正式介绍依赖范围之前,我们需要知道一件事,那就是:Maven 项目的环境变量(classpath)有三种,分别为编译时用的环境变量、测试时用的环境变量和运行时用的环境变量。而依赖范围就是用来控制依赖与这三种环境的关系的:

  • compile:编译依赖范围,此为默认值,对编译、测试和运行三种环境变量都有效。
  • test:测试依赖范围,仅对测试环境变量有效。
  • provided:已提供的依赖范围,对编译和测试环境变量都有效。
  • runtime:运行依赖范围,对测试和运行环境变量都有效。
  • system:系统依赖范围,对编译和测试环境变量都有效,但由于此依赖不是通过 Maven 仓库解析的,而且往往与本机系统绑定,可能造成构建的不可移植,因此应该谨慎使用。
  • import:导入依赖范围,并不会对上面的三种环境变量产生实际的影响。
    在这里插入图片描述
             上表为 Maven 的直接依赖范围。除此之外,还有传递性依赖,那么何为传递性依赖呢?
             在默认依赖范围的情况下,如果项目 A 依赖 B,B 依赖 C,那么 A 就依赖 C,这时 A 与 C 就是传递性依赖的关系。而且我们称 A 对 B 的依赖为第一直接依赖,B 对 C 的依赖为第二直接依赖,以此类推。
             至于为什么要强调在默认依赖范围的情况下,则是传递性依赖也是有条件的,具体如下表所示:
    在这里插入图片描述
             观察上表,我们会发现:当第二直接依赖为compile时,则依赖关系以第一直接依赖为准;当第二直接依赖为test时,则没有依赖关系;当第二直接依赖为provided时,只有第一直接依赖也为provided时才有provided范围的依赖关系;当第二直接依赖为runtime时,除了第一直接依赖关系为compile时依赖范围为runtime,其他三种皆与第一直接依赖范围相同。

3 依赖原则

         maven对于依赖相同的资源,默认会做出以下优化:

3.1 第一原则:以短路径长度为准

         例如,项目A有这样的依赖关系 : A–>B–>C–>X(1.0)、A–>D–>X(2.0),X是A的传递性依赖,但是两条依赖路径上有两个版 本的X,那么哪个X会被maven解析使用呢?两个版本都被解析显然是不对的,因为那会造成依赖重复,因此必须选择一个。maven依赖调解的第一原则:路径最近者优先。该例中X(1.0)的路径长度为3,而X(2.0)的路径长度为2,因此X(2.0)会被解析使用。

3.2 第二原则:相同路径长度时,以pom中声明顺序先者为准

         依赖调解第一原则不能解决所有问题,比如这样的依赖关系:A–>B–>Y(1.0),A–>C–>Y(2.0),Y(1.0)和Y(2.0)的依赖路径长度是一样的,都为2。那么到底谁会被解析使用呢?在maven2.0.8及之前的版本中,这是不确定的,但是maven2.0.9开始,为了尽可能避免构建的不确定性,maven定义了依赖调解的第二原则:第一声明者优先。在依赖路径长度相等的前提下,在POM中依赖声明的顺序决定了谁会被解析使用。顺序最靠前的那个依赖优胜。

4 依赖冲突解决

4.1 何为依赖冲突

         Maven是个很好用的依赖管理工具,但是再好的东西也不是完美的。Maven的依赖机制会导致Jar包的冲突。举个例子,现在你的项目中,使用了两个Jar包,分别是A和B。现在A需要依赖另一个Jar包C,B也需要依赖C。但是A依赖的C的版本是1.0,B依赖的C的版本是2.0。这时候,Maven会将这1.0的C和2.0的C都下载到你的项目中,这样你的项目中就存在了不同版本的C,这时Maven会依据依赖路径最短优先原则,来决定使用哪个版本的Jar包,而另一个无用的Jar包则未被使用,这就是所谓的依赖冲突。
         在大多数时候,依赖冲突可能并不会对系统造成什么异常,因为Maven始终选择了一个Jar包来使用。但是,不排除在某些特定条件下,会出现类似找不到类的异常,所以,只要存在依赖冲突,在我看来,最好还是解决掉,不要给系统留下隐患。

4.2 解决思路

  • 声明优先原则
  • 就近优先原则
  • 排除依赖

4.3 解决方法

         解决依赖冲突的方法,就是使用Maven提供的标签,标签需要放在标签内部,就像下面这样:

	<dependency>
	    <groupId>org.apache.logging.log4j</groupId>
	    <artifactId>log4j-core</artifactId>
	    <version>2.10.0</version>
	    <exclusions>
	        <exclusion>
	        <artifactId>log4j-api</artifactId>
	        <groupId>org.apache.logging.log4j</groupId>
	        </exclusion>
	    </exclusions>
	</dependency>

4.4 使用Maven Helper解决Maven依赖冲突

         如何才能知道自己的项目中哪些依赖的Jar包冲突了呢?Maven Helper这个InteliJ IDEA的插件帮我们解决了这个问题。插件的安装方法我就不讲了,既然你都会Maven了,我相信你也是会安装插件的。
         在插件安装好之后,我们打开pom.xml文件,在底部会多出一个Dependency Analyzer选项
在这里插入图片描述
点开这个选项
在这里插入图片描述
找到冲突,点击右键,然后选择Exclude即可排除冲突版本的Jar包。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值