Maven直接依赖、间接依赖、依赖冲突、依赖仲裁的实现

 更新时间:2023年09月21日 15:46:54   作者:ares5k  
本文主要介绍了Maven直接依赖、间接依赖、依赖冲突、依赖仲裁的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

直接依赖和间接依赖

在项目中直接引入的依赖叫做直接依赖,而那些被动引入的就叫间接依赖

直接依赖和间接依赖

比如上图中,A 是我们的项目,我们在项目中直接引入了 B 模块,所以 B 和 A 的关系就是直接依赖,而 B 工程内部引入了 C,所以 B 和 C 也是直接依赖关系,如果 B 工程在引入 C 时,指定了 C 模块的依赖范围是 <scope>compile</scope> ,那么 C 模块就会随着 B 模块一同被引入到我们的工程A 中,这时候 A 和 C 的关系就是间接依赖

依赖冲突

Maven 的依赖冲突,我认为有两种情况,Maven 能自动解决的、需要手动解决的

1. Maven 可以自动解决的依赖冲突

在项目中,不管是直接依赖还是间接依赖,当有多个 <groupId> <artifactId> 相同, <version> 不同的依赖引入时,Maven 就会认为我们引入了相同模块的不同版本,其就会被判定为依赖冲突,这种情况 Maven 会用自己的仲裁机制帮我们取舍

2. 需要手动解决的依赖冲突

模块间的 <groupId> <artifactId> <version> 都不相同,但是引入的这些模块中具有相同路径的类(包名+类名完全相同),这个时候就需要我们自己去解决依赖冲突问题

Maven 的依赖仲裁

依赖仲裁是 Maven 自动解决依赖冲突的手段,我们想更好的利用它,就必须知道其仲裁的规则,其通过 最短路径优先 先声明优先 两个依据来判断最终留下的模块

最短路径优先

当项目的依赖树中存在相同模块的不同版本时,Maven 的仲裁机制就会介入,其首先会通过最短路径的方式来对冲突的模块进行取舍,如下图,假设我们的项目是A,明显C模块发生了依赖冲突,那么按照最短路径优先的原则,Maven 最后会留下 A → B → C 1.0 这个路径下的 C 模块

最短路径优先

先声明优先

当两个依赖冲突的模块,其路径距离相同时,就会使用先声明优先的规则,这个就很简单了,就是留下先声明的模块,如下图,假设我们的项目是A,两个冲突的模块C到 A 的距离是相同的,这时 Maven 就会根据先声明优先的规则选择A → B → C 1.0 这个路径下的 C 模块,因为其声明在前

先声明优先

至于什么叫先声明,非常简单,用上图例子,我写个伪代码

<!-- 这个 B 的依赖信息就是先声明的,所以仲裁后会留下B模块中依赖的C模块 -->
<dependency>
    <groupId>B</groupId>
    <artifactId>B</artifactId>
    <version>release</version>
</dependency>
<dependency>
    <groupId>D</groupId>
    <artifactId>D</artifactId>
    <version>release</version>
</dependency>

了解仲裁规则后,也可以利用 Maven 的仲裁规则,保留自己想要的模块,比如上面例子中,我们想保留模块 C 2.0,那么就可以将模块 C 2.0 的依赖信息主动声明在依赖列表的最前面,这样不论是最短路径规则还是先声明的规则,都会判定 C 2.0 被保留,伪代码如下:

<!--在依赖列表的最前面主动声明模块C2.0的依赖信息-->
<dependency>
    <groupId>C</groupId>
    <artifactId>C</artifactId>
    <version>2.0</version>
</dependency>
<dependency>
    <groupId>B</groupId>
    <artifactId>B</artifactId>
    <version>release</version>
</dependency>
<dependency>
    <groupId>D</groupId>
    <artifactId>D</artifactId>
    <version>release</version>
</dependency>

手动解决依赖冲突

需要手动解决的情况,是指不同模块中,具有相同路径的类(包名和类名完全相同),从而导致项目启动后,类加载器加载了同名的非目标类,从而出现 ClassNotFoundException NoClassDefFoundError LinkageError 等类似的错误

手动解决依赖冲突,首先需要找出路径相同的类所在的模块,其次决定要留用的模块

找出类路径相同的模块

可以借助 Maven 的生命周期插件 maven-enforcer-plugin

1. 在项目的 Pom.xml 中添加配置

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-enforcer-plugin</artifactId>
            <version>1.4.1</version>
            <executions>
                <execution>
                    <id>enforce-dependencies</id>
                    <phase>validate</phase>
                    <goals>
                        <goal>display-info</goal>
                        <goal>enforce</goal>
                    </goals>
                </execution>
            </executions>
            <dependencies>
                <dependency>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>extra-enforcer-rules</artifactId>
                    <version>1.0-beta-4</version>
                </dependency>
            </dependencies>
            <configuration>
                <rules>
                    <banDuplicateClasses>
                        <findAllDuplicates>true</findAllDuplicates>
                    </banDuplicateClasses>
                </rules>
            </configuration>
        </plugin>
    </plugins>
</build>

(2) 执行 mvn clean package enforcer:enforce 命令后,就能看见重复的类和模块

找到类重复的模块

(3) 找到冲突的模块后,删掉弃用的模块,如果是直接依赖的模块直接删除依赖信息就好,如果是间接依赖的模块,就要使用 <exclusions> 排除依赖传递,方式如下:

<dependency>
    <groupId></groupId>
    <artifactId></artifactId>
    <version></version>
    <!-- 排除依赖传递 -->
    <exclusions>
        <exclusion>
            <groupId>要弃用的模块的groupId</groupId>
            <artifactId>要弃用的模块的artifactId</artifactId>
        </exclusion>
    </exclusions>
</dependency>

到此这篇关于Maven直接依赖、间接依赖、依赖冲突、依赖仲裁的实现的文章就介绍到这了,更多相关Maven直接依赖、间接依赖、依赖冲突、依赖仲裁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 浅析SpringBoot统一返回结果的实现

    浅析SpringBoot统一返回结果的实现

    前后端开发过程中数据交互规范化是一件非常重要的事情,不仅可以减少前后端交互过程中出现的问题,也让代码逻辑更加具有条理,下面小编就和大家讲讲SpringBoot如何统一返回结果的吧
    2023-07-07
  • 详解Java多线程与并发

    详解Java多线程与并发

    多线程是一个进程在执行过程中产生多个更小的程序单元,这些更小的单元称为线程,这些线程可以同时存在,同时运行,一个进程可能包含多个同时执行的线程。多线程是实现并发机制的一种有效手段。进程和线程一样,都是实现并发的一个基本单位。
    2021-06-06
  • JAVA中的FileWriter流解析

    JAVA中的FileWriter流解析

    这篇文章主要介绍了JAVA中的FileWriter流解析,FileWriter类提供了多种写入字符的方法,包括写入单个字符、写入字符数组和写入字符串等,它还提供了一些其他的方法,如刷新缓冲区、关闭文件等,需要的朋友可以参考下
    2023-10-10
  • springboot项目父子多模块打包方式

    springboot项目父子多模块打包方式

    这篇文章主要介绍了springboot项目父子多模块打包方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • JMeter断言之json断言解读

    JMeter断言之json断言解读

    这篇文章主要介绍了JMeter断言之json断言问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • Eclipse如何导入Maven项目详解(新手初学)

    Eclipse如何导入Maven项目详解(新手初学)

    这篇文章主要介绍了Eclipse如何导入Maven项目详解(新手初学),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-12-12
  • HttpClient 在Java项目中的使用详解

    HttpClient 在Java项目中的使用详解

    HttpClient作为访问Http服务的客户端访问程序已经被广泛使用,提高了开发效率,也提高了代码的健壮性。因此熟练掌握HttpClient是必需的,关于httpclient感兴趣的朋友可以参考本篇文章
    2015-10-10
  • MyBatis-Plus使用ActiveRecord(AR)实现CRUD

    MyBatis-Plus使用ActiveRecord(AR)实现CRUD

    本文将结合实例代码,介绍MyBatis-Plus使用ActiveRecord(AR)实现CRUD,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧
    2021-07-07
  • Java实现微信公众号自定义菜单的创建方法示例

    Java实现微信公众号自定义菜单的创建方法示例

    这篇文章主要介绍了Java实现微信公众号自定义菜单的创建方法,结合实例形式分析了java创建微信公众号自定义菜单的具体步骤、实现方法及相关操作注意事项,需要的朋友可以参考下
    2019-10-10
  • java排查死锁示例

    java排查死锁示例

    这篇文章主要介绍了java排查死锁示例,通过java中简单的死锁示例引出四种排查死锁的工具,详细讲解请看全文,希望对大家有所帮助
    2021-08-08

最新评论