一、什么是Maven中的依赖冲突
我们在第五篇Maven实战-第五篇(Maven的传递性依赖)
中介绍了Maven中传递性依赖的内容。并且通过上一篇的内容我们也了解到了传递性依赖为我们使用Maven所带来的好处。但是同样的传递性依赖也为我们带来了使用的弊端,也就是Maven中的依赖冲突。那什么是依赖冲突呢?假如我们有一个项目A。它依赖于项目X。还有一个项目B也依赖于项目X。但是呢这两个项目所依赖X的版本不一致。但是Maven中又支持传递性依赖,所以按照正常的逻辑,这两个X的版本的项目都会引入到项目中,但这样就会造成依赖冲突。因为项目中有两个一样的依赖只是版本不同,所以Maven就不知道引入哪个依赖了,这就是Maven中的依赖冲突。
二、怎么解决Maven的依赖冲突
所以在Maven中为了解决上面说的依赖冲突引入了一个概念就是依赖调节,其实也就是解决依赖冲突的一个默认规则。因为我们知道,依赖冲突的本质是传递性依赖的版本不一致导致的。所以我们只要制定一个规则,来让Maven可以选择一个传递性依赖的版本就可以了。Maven就是通过这样的方式解决依赖冲突的。下面我们详细介绍一下这个规则到底是什么。
规则一
这个规则就是引入依赖的路径近者优先。举例来说就是如果项目的依赖路径是这样的:A->B-C-X(1.0)。然后还有一个项目依赖路径为A->D->X(2.0)。按照上面引入依赖的路径来判断,我们知道后者的路径较短。所以Maven在执行传递性依赖时会按照上述的规则引入X(2.0)的版本依赖。
下面我们通过一个例子来验证一上上面所说的规则。我们以上个项目为例,创建4个项目它们分别是:mazhe-maven-mall、mazhe-maven-order、mazhe-maven-user、mazhe-maven-payment
。其中它们的依赖关系是mazhe-maven-mall
依赖于mazhe-maven-order
和mazhe-maven-payment
,而mazhe-maven-order
又依赖于mazhe-maven-user
。这样我们就模拟出来依赖路径不一样的,来验证规则一。具体配置如下:
1、mazhe-maven-mall
- pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>midai-mazhe-maven</artifactId>
<groupId>cn.ma-zhe</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mazhe-maven-mall</artifactId>
<dependencies>
<dependency>
<groupId>cn.ma-zhe</groupId>
<artifactId>mazhe-maven-order</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.ma-zhe</groupId>
<artifactId>mazhe-maven-payment</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
2、mazhe-maven-order
- pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>midai-mazhe-maven</artifactId>
<groupId>cn.ma-zhe</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mazhe-maven-order</artifactId>
<dependencies>
<dependency>
<groupId>cn.ma-zhe</groupId>
<artifactId>mazhe-maven-user</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
3、mazhe-maven-payment
- pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>midai-mazhe-maven</artifactId>
<groupId>cn.ma-zhe</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mazhe-maven-payment</artifactId>
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.32</version>
</dependency>
</dependencies>
</project>
4、mazhe-maven-user
- pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>midai-mazhe-maven</artifactId>
<groupId>cn.ma-zhe</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mazhe-maven-user</artifactId>
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.35</version>
</dependency>
</dependencies>
</project>
通过上面的配置,我们分别在mazhe-maven-payment
和mazhe-maven-user
中引入了fastjson
的依赖,并且为了模拟依赖冲突,我们将这两个项目所依赖的fastjson
的版本设置成了不一样的版本,其中mazhe-maven-payment
的版本为:2.0.32
,而mazhe-maven-user
的版本为:2.0.35
。下面我们验证一下,当这样的依赖冲突后,我们mazhe-maven-mall
项目依赖的版本到底是多少。我们还是通过Show Deagram ...
的方式来查看mazhe-maven-mall
项目的依赖情况。
通过上图我们也发现IDEA中已经将这两个依赖冲突的版本显示出来了并且非常直观的标识出了mazhe-maven-user
项目依赖的fastjson
的依赖已经指向了mazhe-maven-payment
的fastjson
版本。所以此时mazhe-maven-mall
项目通过传递性依赖所引入的fastjson
版本就是2.0.32
。如果我们将mazhe-maven-payment
和mazhe-maven-user
依赖的版本进行一下对换。在查看一下就会发现,mazhe-maven-mall
项目所依赖的版本就会变成2.0.35
了。
这就是Maven中解决依赖冲突的第一个规则,最短路径原则,因为项目mazhe-maven-payment
依赖的fastjson
的路径最短,所以传递性依赖以mazhe-maven-payment
项目配置的版本为准。
规则二
当然这不能解决所有依赖冲突的问题,因为如果项目依赖路径相同时,上面的规则就不起作用了。所以为了解决这个问题。Maven又引入了第二条规则。当第一条规则不能解决依赖冲突时,第二条规则则会起作用。在Maven中规定,如果项目依赖的路径相同时,Maven以依赖声明的顺序决定依赖冲突。也就是说,如果项目依赖的路径相同,则谁先引入这个依赖,Maven就会默认引入这个项目的传递性依赖。
同样的我们还是通过例子的方式来验证一下上面说的内容。我们将上面的代码进行一下修改,直接在mazhe-maven-order
项目中引入fastjson
的依赖,并且它两个项目的版本配置的不一样的。
1、mazhe-maven-order
- pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>midai-mazhe-maven</artifactId>
<groupId>cn.ma-zhe</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mazhe-maven-order</artifactId>
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.35</version>
</dependency>
</dependencies>
</project>
2、mazhe-maven-payment
- pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>midai-mazhe-maven</artifactId>
<groupId>cn.ma-zhe</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mazhe-maven-payment</artifactId>
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.32</version>
</dependency>
</dependencies>
</project>
3、mazhe-maven-mall
- pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>midai-mazhe-maven</artifactId>
<groupId>cn.ma-zhe</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mazhe-maven-mall</artifactId>
<dependencies>
<dependency>
<groupId>cn.ma-zhe</groupId>
<artifactId>mazhe-maven-order</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.ma-zhe</groupId>
<artifactId>mazhe-maven-payment</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
下面我们用同样的方式,看一下mazhe-maven-mall
项目的依赖。
如图所示,Maven引入的传递性依赖fastjson
的版本为:2.0.35
。下面我们将mazhe-maven-mall
项目中依赖的顺序调换一下。
- pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>midai-mazhe-maven</artifactId>
<groupId>cn.ma-zhe</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mazhe-maven-mall</artifactId>
<dependencies>
<dependency>
<groupId>cn.ma-zhe</groupId>
<artifactId>mazhe-maven-payment</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.ma-zhe</groupId>
<artifactId>mazhe-maven-order</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
我们在查看一下mazhe-maven-mall
项目的依赖情况。
我们看这次mazhe-maven-mall
项目的依赖版本就变成了:2.0.32
了。这也就是Maven为了解决依赖冲突制定的第二个规则。按照配置依赖的顺序决定传递性依赖的版本。
三、Maven中怎么排除依赖
就是因为传递性依赖的原因,在使用Maven时常常会引入很多额外的依赖包。Maven这么做的目的当然是为了方便了我们依赖管理。但这样也会导致一些其它的问题。例如如果传递性依赖引入了一些其它版本的依赖包。但因为有些原因,实际的的项目中却不能引入这个版本的依赖包,需要引入其它版本的依赖包。那该如何解决呢?在Maven中为了解决这样的问题,引入了排除传递性依赖的方式,也就是在Maven中可以使用exclusions
标签来排除传递性依赖。当通过下面的方式配置后,Maven将不在进行传递性依赖了。具体的配置如下:
<dependencies>
<dependency>
<groupId></groupId>
<artifactId></artifactId>
<version></version>
<exclusions>
<exclusion>
<groupId></groupId>
<artifactId></artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
我们还是以刚刚的例子为例,因为我们在项目中有引入了mazhe-maven-payment
依赖,所以在路径相同时,Maven会直接引入这个项目的依赖包。我们通过下面的配置将mazhe-maven-payment
项目依赖fastjson
的包排除掉,然后在看一下依赖情况。具体配置如下:
1、mazhe-maven-mall
- pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>midai-mazhe-maven</artifactId>
<groupId>cn.ma-zhe</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mazhe-maven-mall</artifactId>
<dependencies>
<dependency>
<groupId>cn.ma-zhe</groupId>
<artifactId>mazhe-maven-payment</artifactId>
<version>1.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>cn.ma-zhe</groupId>
<artifactId>mazhe-maven-order</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
我们在查看一下mazhe-maven-mall
项目的依赖情况。
我们看上图所示,IDEA中已经不会提示依赖冲突了,因为当前传递性依赖中只有一个版本的fastjson
依赖,所以也就不会提示依赖冲突了,这就是Maven中提供排除依赖的目的。
我们通过上面的配置发现Maven在排除依赖的时候,是不需要我们指定排除的版本的。有人知道这是为什么吗?这是因为我们传递性依赖所传递的版本已经确定了,因为它会在依赖包中指定我们依赖的版本,所以在排除时,就不需要我们指定版本了,因为一定只有一个版本。