Maven

面对他,消灭他-搞定Maven依赖冲突

2020-04-10  本文已影响0人  晏子小七

因:

了解出现Maven依赖冲突的原因首先了解一下Maven的仲裁机制:

原因总结:

  1. 传递依赖导致不同的jar包冲突——maven会采用‘最短路径’选择jar。如果排除的是旧版本的jar包,直接调用最新jar有的方法,就会报ClassnotFound错误。


    最短路径

    如图,我们显示依赖了 spring-boot1.5.9,和spring-core4.0.8(当然这种情况在正常情况下不会发生)
    在这种情况,根据Maven的最短依赖路径原则,会使用spring-core4.0.8
    当在启动项目的时候会报错:


    项目报错
  1. 不同的jar包,出现相同的类路径,此时JVM运行时会不知道执行哪个类,会报 java.lang.AbstractMethodError: javax.xml.parsers.DocumentBuilderFactory.setFeature(Ljava/lang/String;Z)V类似运行时异常。
  2. 在运行期,很有可能出现依赖A在执行过程中调用C(1.0)以前有但是升级到C(1.1)就缺失的类c,导致运行期失败,出现很典型的依赖冲突时的NoClassDefFoundError错误。
  3. 如果是升级后出现原有的方法被修改而不存在的情况时,就会抛出NoSuchMethodError错误。

解:

  1. 首先可以借助Maven查看依赖的依赖树来分析一下:手动:mvn dependency:tree,或者使用IDEA的Maven Helper插件Dependency Analyzer插件来可视化地分析依赖关系,或者 mvn dependency:tree -Dverbose查看依赖树。这个过程后可以明确哪些dependency引入了可能会冲突的依赖。


    analyzer解决冲突
  2. Maven Helper插件就找到冲突jar包,然后在对应标红版本的jar包上面点击execlude,就可以将该jar包排除出去。


    dependencytree
  3. 使用ctrl+shift+alt+n 查找类路径所在的jar包,把对应的jar包在pom中排除。

其他解决方案:

①. 统一版本:为jar包指定一个版本,所有用到的都会是这个版本。操作如下:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>4.0.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>4.0.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>4.0.0.RELEASE</version>
</dependency>

统一配置:

<properties>
    <spring.version>4.1.1.RELEASE</spring.version>
</properties>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>${spring.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>${spring.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>${spring.version}</version>
</dependency>

②. 排除加载:就是在别的用到这个jar包的地方加上说明,告诉它不用自己加载依赖用别人的。 如下: 如果我们不想通过 A->B->C>D1 引入 D1 的话,那么我们在声明引入 A 的时候将 D1 排除掉 举个例子:将 zookeeper 的 jline 依赖排除

    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>zookeeper</artifactId>
        <version>3.3.1</version>
        <exclusions>
            <exclusion>
                <groupId>jline</groupId>
                <artifactId>jline</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

上一篇 下一篇

猜你喜欢

热点阅读