maven jar包冲突原理与解决办法

jar 包冲突原因

Caused by:java.lang.NoSuchMethodError
Caused by: java.lang.ClassNotFoundException

大概就是jar包冲突(今天遇到的是第一种)

因为Maven拥有传递依赖的特性,因此真实的依赖树是:

依赖传递问题:

  • 当依赖层级很深的时候,可能造成循环依赖(cyclic dependency)
  • 当依赖的数量很多的时候,依赖树会非常大
  • 查找依赖冲突

    idea插件 dependency analyzer插件,如下图,可以清晰的看到依赖树,进而决定如何解决

    A项目通过依赖传递依赖了两个版本的D:
    A -> B -> C -> ( D 2.0) , A -> E -> (D 1.0)
    那么最终A依赖的D的version将会是1.0,因为1.0对应的层级更少,也就是更近。

    Dependency management,可以大大简化子POM的依赖声明。
    即父pom.xml声明版本,子pom.xml
    不用指定版本号。

  • 依赖范围(Dependency scope)
  •      <scope>system</scope>
    

    有以下参数

  • compile: 编译依赖范围(默认)
  • test: 测试依赖范围 典型例子是JUnit,它只有在编译测试代码及运行测试的时候才需要
  • provided: 已提供依赖范围
    使用此依赖范围的Maven依赖,对于编译和测试classpath有效,但在运行时无效。
    典型例子是servlet-api,编译和测试项目的时候需要该依赖,但在运行项目的时候,由于容器已经提供,就不需要Maven重复地引入一遍。
  • runtime: 运行时依赖范围。
    使用此依赖范围的Maven依赖,对于测试和运行classpath有效,但在编译主代码时无效。
    典型例子是JDBC驱动实现,项目主代码的编译只需要JDK提供的JDBC接口,只有在执行测试或者运行项目的时候才需要实现上述接口的具体JDBC驱动。
  • 排除依赖(Excluded dependencies)

    排除不需要从所依赖的项目中传递过来的依赖 <exclude/>

    可选依赖(Optional dependencies)

    被依赖的项目主动不把可以传递的依赖传递下去

    使用Maven提供的Optional和Exclusions来控制依赖的传递
    Optional 定义后,该依赖只能在本项目中传递,不会传递到引用该项目的父项目中,父项目需要主动引用该依赖才行。

    A/pom.xml如下:

    <dependency>
        <groupId>com.zxa</groupId>
        <artifactId>B</artifactId>
        <version>1.0</version>
        <optional>true</optional>
    </dependency>
    

    这种情况下,此项目对B的依赖将不会传递给D
    Exclusions 则是主动排除子项目传递过来的依赖。

    <dependency>
        <groupId>com.bar</groupId>
        <artifactId>A</artifactId>
        <version>1.0</version>
        <exclusions>
            <exclusion>
                <groupId>com.bar</groupId>
                <artifactId>B</artifactId>