Apache Maven依赖的传递性、依赖的排除、版本仲裁、jar包冲突解决

1. 依赖的传递性

1.1 概念

A依赖B,B依赖C,那么A能不能直接使用C

1.2 传递的原则

A依赖B,B依赖C,A能不能直接使用C,取决于B依赖C时使用的依赖范围scope

  • B依赖C时使用compile:A能直接使用C
  • B依赖C时使用test或provided范围,A不能直接使用C

2. 依赖的排除

2.1 概念

当A依赖B,A又依赖C,但B和C依赖一个包的两个不同版本,这就可能发生版本冲突,需要使用依赖排序将其中一个排除掉

版本冲突

2.2 配置方式

下面例子是iceberg-flink不引入slf4j-api的依赖传递

    <dependency>
      <groupId>org.apache.iceberg</groupId>
      <artifactId>iceberg-flink</artifactId>
      <version>0.13.2</version>
      <exclusions>
        <exclusion>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-api</artifactId>
        </exclusion>
      </exclusions>
    </dependency>

3. 版本仲裁

遵循以下原则:
1. 最短路径优先

在下面的例子中,对模块pro25-module-a来说,Maven会采用1.2.12版本

最短路径优先
2. 路径相同时先声明者优先

在下面的例子中,在pro29-module-x中,先对pro30-module-y进行依赖声明,再对pro31-module-z进行依赖声明。所以Maven会采用1.2.17版本

先声明者优先

4. jar包冲突

4.1 jar包冲突原因

主要体现为找不到类或找不到方法

  • 抛异常:找不到类

此时抛出的常见的异常类型:

java.lang.ClassNotFoundException:编译过程中找不到类
java.lang.NoClassDefFoundError:运行过程中找不到类
java.lang.LinkageError:不同类加载器分别加载的多个类有相同的全限定名

原因:假如我们需要类A,在B-1.1.jar包中。但通过版本仲裁,采用了B-1.0.jar。而B-1.0.jar没有类A,就会抛找不到类A的异常

  • 抛异常:找不到方法

程序找不到符合预期的方法。这种情况多见于通过反射调用方法,所以经常会导致:java.lang.NoSuchMethodError

  • 没报错但结果不对

发生这种情况比较典型的原因是:两个jar包中的类分别实现了同一个接口,而这两个实现类恰巧是同一个名字。本来想使用第一个,确使用了第二个,虽然没报错,但由于实现细节不一样,导致结果不对

4.2 解决办法

基本思路主要有两步:

  1. 把彼此冲突的jar包找到
  2. 在冲突的jar包中选定一个。具体可以通过exclusions排除依赖,或明确声明依赖

4.2.1 IDEA的Maven Helper插件的使用

能够给我们罗列出来同一个jar包的不同版本,以及它们的来源。但是对不同jar包中同名的类没有办法

先安装Maven Helper插件
Maven Helper完整的pom.xml内容如下:

<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">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.hh</groupId>
  <artifactId>maven-learn</artifactId>
  <version>0.1</version>

  <dependencies>
    <dependency>
      <groupId>org.apache.flink</groupId>
      <artifactId>flink-core</artifactId>
      <version>1.15.0</version>
    </dependency>

    <dependency>
      <groupId>com.ververica</groupId>
      <artifactId>flink-connector-mysql-cdc</artifactId>
      <version>2.2.0</version>
    </dependency>

  </dependencies>

</project>

查看冲突的依赖如下
查看冲突的依赖

4.2.2 Maven的enforcer插件使用

既可以检测同一个jar包的不同版本,又可以检测不同jar包中同名的类

添加maven-enforcer-plugin插件到pom.xml,并添加extra-enforcer-rules插件依赖,然后开启重复的类检测功能

完整的pom.xml内容如下:

<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">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.hh</groupId>
  <artifactId>maven-learn</artifactId>
  <version>0.1</version>

  <dependencies>
    <dependency>
      <groupId>org.apache.flink</groupId>
      <artifactId>flink-core</artifactId>
      <version>1.15.0</version>
    </dependency>

    <dependency>
      <groupId>com.ververica</groupId>
      <artifactId>flink-connector-mysql-cdc</artifactId>
      <version>2.2.0</version>
    </dependency>

  </dependencies>

  <build>
    <pluginManagement>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-enforcer-plugin</artifactId>
          <version>3.0.0-M3</version>
          <executions>
            <execution>
              <id>enforce-dependencies</id>
              <phase>validate</phase>
              <goals>
                <goal>display-info</goal>
                <goal>enforce</goal>
              </goals>
            </execution>
          </executions>
          <dependencies>
            <!-- 官网地址:http://www.mojohaus.org/extra-enforcer-rules/index.html -->
            <!-- 1.3版本和maven-enforcer-plugin的3.0.0、3.1.0两个版本不兼容 -->
            <dependency>
              <groupId>org.codehaus.mojo</groupId>
              <artifactId>extra-enforcer-rules</artifactId>
              <version>1.3</version>
            </dependency>
          </dependencies>
          <configuration>
            <rules>
              <!-- banDuplicateClasses由extra-enforcer-rules提供 -->
              <banDuplicateClasses>
                <findAllDuplicates>true</findAllDuplicates>
              </banDuplicateClasses>
            </rules>
          </configuration>

        </plugin>
      </plugins>
    </pluginManagement>
  </build>


</project>

执行如下命令进行重复类检测

C:\Users\dell\Desktop\maven-learn>mvn clean enforcer:enforce
[INFO] Scanning for projects...
[INFO] 
[INFO] -------------------------< com.hh:maven-learn >-------------------------
[INFO] Building maven-learn 0.1
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ maven-learn ---
[INFO] 
[INFO] --- maven-enforcer-plugin:3.0.0-M3:enforce (default-cli) @ maven-learn ---
[INFO] Adding ignore: module-info
[INFO] Adding ignore: META-INF/versions/*/module-info
[WARNING] Could not find com.ververica:flink-connector-mysql-cdc:jar:2.2.0:compile at null
[WARNING] Could not find org.apache.flink:flink-core:jar:1.15.0:compile at null
[WARNING] Rule 0: org.apache.maven.plugins.enforcer.BanDuplicateClasses failed with message:
Duplicate classes found:

  Found in:
    javax.xml.bind:jaxb-api:jar:2.3.0:compile
    jakarta.xml.bind:jakarta.xml.bind-api:jar:2.3.2:compile
  Duplicate classes:
    javax/xml/bind/annotation/XmlValue.class
    javax/xml/bind/ContextFinder.class
......省略部分......
    javax/xml/bind/helpers/AbstractMarshallerImpl.class

  Found in:
    com.ververica:flink-connector-debezium:jar:2.2.0:compile
    io.debezium:debezium-embedded:jar:1.5.4.Final:compile
  Duplicate classes:
    io/debezium/embedded/EmbeddedEngineChangeEvent.class

  Found in:
    javax.ws.rs:javax.ws.rs-api:jar:2.1.1:compile
    jakarta.ws.rs:jakarta.ws.rs-api:jar:2.1.6:compile
  Duplicate classes:
    javax/ws/rs/ext/RuntimeDelegate$HeaderDelegate.class
    javax/ws/rs/HEAD.class
......省略部分......
    javax/ws/rs/client/CompletionStageRxInvoker.class

  Found in:
    jakarta.activation:jakarta.activation-api:jar:1.2.1:compile
    javax.activation:activation:jar:1.1.1:compile
  Duplicate classes:
    javax/activation/DataContentHandlerFactory.class
    javax/activation/SecuritySupport$2.class
......省略部分......
    javax/activation/URLDataSource.class

[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  2.215 s
[INFO] Finished at: 2022-07-01T16:06:35+08:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-enforcer-plugin:3.0.0-M3:enforce (default-cli) on project maven-learn: Some Enforcer rules
 have failed. Look above for specific messages explaining why the rule failed. -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException

C:\Users\dell\Desktop\maven-learn>

这里虽然构建失败,但是不影响我们查看重复的类

4.3 用父工程做dependencyManagement统一管理依赖

推荐一个公司或部门,用一个父工程做dependencyManagement,统一管理依赖关系,其它项目只需引用即可,避免每个人都去解决jar包冲突的问题。如果出现jar包冲突问题,只需修改该父工程的dependencyManagement就可以了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值