依赖冲突 NoSuchMethodError:org.apache.logging.log4j.Logger.debug(Ljava/lang/String;Ljava/lang/Object;)V

Intro

我是在引入了ElasticSearch的相关依赖之后出现了这个错误,问题的本质是出现了依赖冲突

  • env
    org.elasticsearch.client:elasticsearch-rest-high-level-client:6.1.1
    org.elasticsearch:elasticsearch-analysis-ik:6.1.1
    IDE: eclipse

程序报错说Logger没有debug(String, Object)方法。具体的Failure Trace如下:
在这里插入图片描述

解决

  • 查看POM依赖项
    在这里插入图片描述注意此时在pom.xml选项。
    注意这两个依赖:
<!-- ES REST 高级客户端 -->
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>6.1.1</version>
</dependency>
<!-- IK中文分词器 -->
<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch-analysis-ik</artifactId>
    <version>6.1.1</version>
</dependency>
  • 切换到Dependency Hierarchy(下边缘找),查看各个依赖项的层次。
    右上角Filter中搜索log4j-api,可见:
    在这里插入图片描述在这个可视化的界面中(IDEA中也有类似的依赖传递关系的可视化工具),可知:
    org.elasticsearch.client:elasticsearch-rest-high-level-client:6.1.1间接依赖于2.9.1版本的log4j-api
    org.elasticsearch:elasticsearch-analysis-ik:6.1.1依赖于2.3版本的log4j-api,这就产生了依赖冲突(同一个依赖,有多个版本(包括直接依赖和传递依赖))。

而Maven作为一个集中管理依赖的工具,其解决依赖冲突有两个原则:
- 第一原则:就近原则,层级浅的依赖优先。
- 第二原则:先到先得,同层级的多个依赖,谁最先声明,谁就被启用。(所以说Maven配置中,依赖项的前后声明顺序也是有影响的)。
在本案例中,IK分词器直接依赖于2.3版本的log4j-api,而es高级REST客户端和2.9.1版本的log4j-api隔了两层。
所以根据第一原则,Maven选择了2.3版本。
2.9.1版本的log4j-api可以看到:ommitted for the conflict with 2.3,因为和2.3版本产生了冲突1.9.1版本所以被忽略了。
那么下一步很清晰:启用合适的log4j-api依赖库。

  • 解决方案
    我的选择是:启用较新的2.9.1版本的log4j-api,去除2.3版本。
    Maven解决依赖冲突的方法有多种,此处只介绍两种。
    1. 对引入的IK分词器,使用<exclusions>标签排除其子依赖log4j-api。
    2. 通过maven的依赖管理,指定我们要使用的log4j-api的版本,使用标签为dependencyManagement
      推荐第二种。
      这两种方法都可以在eclipse中自动完成:在刚才的界面里,右击两个log4j-api依赖项,选择对应的选项即可生成对应的代码。
    3. 右击要去除的2.3版本,选择Exclude Maven Artifact
<!-- IK中文分词器 -->
<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch-analysis-ik</artifactId>
    <version>6.1.1</version>
    <exclusions>
    	<exclusion>
    		<groupId>org.apache.logging.log4j</groupId>
    		<artifactId>log4j-api</artifactId>
    	</exclusion>
    </exclusions>
</dependency>

可以看到,IK分词器的依赖项中,自动加入了以下代码:

<exclusions>
	<exclusion>
		<groupId>org.apache.logging.log4j</groupId>
		<artifactId>log4j-api</artifactId>
	</exclusion>
</exclusions>
2. 右击要留下的2.9.1版本,选择`Lock Transitive Dependency Version...`

在这里插入图片描述这会在<dependencies>...<dependencies>节点之添加<dependencyManagement>节点,用于指定某个依赖项的版本。

<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-api</artifactId>
			<version>2.9.1</version>
		</dependency>
	</dependencies>
</dependencyManagement>

要特别注意:pom.xml文件中的节点顺序问题。

More

  • 依赖冲突会导致的两种高频异常
    在我搜索的过程中,发现有其他版本的ElasticSearch用户也在查这个Bug(比如5.X版本)。看来版本冲突的问题影响到了不少人。
    如果代码运行抛出以下两种错误,则应该优先考虑:是不是发生了版本冲突?如果是,解决过程见上。

java.lang.NoSuchMethodError

Thrown if an application tries to call a specified method of a class (either static or instance), and that class no longer has a definition of that method.
Normally, this error is caught by the compiler; this error can only occur at run time if the definition of a class has incompatibly changed.

java.lang.ClassNotFoundException

Thrown when an application tries to load in a class through its string name using:
	The forName method in class Class.
	The findSystemClass method in class ClassLoader .
	The loadClass method in class ClassLoader.
but no definition for the class with the specified name could be found.

这两个异常极有可能是因为依赖冲突问题导致的。所以要善于利用IDE的可视化工具,检查依赖关系。

  • mvn关于依赖的命令
    mvn dependency:list 打印被解析的依赖项的列表
    mvn dependency:tree 打印被解析/启用的依赖项(带缩进)
    mvn dependency:tree -Dverbose 打印所有依赖项(包括因为冲突被忽略omit掉的)
    mvn dependenvy:analyze 分析依赖项
    分析结果,结果分三部分:
    Used undeclared dependencies found 使用了,但未显式声明(的间接依赖)
    Unused declared dependencies found 声明了,但未使用。
    其他。
    最好将那些使用了、但并未显式声明的依赖手动添加到自己的POM配置中
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值