LinkageError解决

思路参考这个回答
在解决依赖冲突的场景中,偶尔会遇到这个问题:

1
2
3
4
java.lang.LinkageError: loader constraint violation: when resolving method "org.slf4j.impl.StaticLoggerBinder.getLoggerFactory()Lorg/slf4j/ILoggerFactory;" the class loader (instance of org/apache/catalina/loader/WebappClassLoader) of the current class, org/slf4j/LoggerFactory, and the class loader (instance of org/apache/catalina/loader/StandardClassLoader) for resolved class, org/slf4j/impl/StaticLoggerBinder, have different Class objects for the type taticLoggerBinder.getLoggerFactory()Lorg/slf4j/ILoggerFactory; used in the signature
at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:299)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:269)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:281)

显然,这是log4j的依赖冲突,但是通过idea的Mavendependency Analyzer并没有找到冲突的依赖,想办法排依赖可能就解决了。然而这种解决方式并不靠谱。这里把问题出现的原因和解决流程记录一下。

排查流程

这个问题是ILoggerFactory这个类被加载了两次

  1. 在jvm参数里添加 -verbose:class, 打印类的加载路径
    找到冲突的jar包
    1
    2
    3
    [Loaded org.slf4j.ILoggerFactory from file:/Users/kunni/.m2/repository/org/slf4j/slf4j-api/1.7.30/slf4j-api-1.7.30.jar]
    ......
    [Loaded org.slf4j.ILoggerFactory from file:/Users/kunni/.m2/repository/org/apache/hive/hive-exec/2.3.8/hive-exec-2.3.8.jar]
    可以看到这个类在slf4j-api-1.7.30.jar和hive-exec-2.3.8.jar上都出现了,可以断定hive-exec-2.3.8.jar里包含了其他版本的slf4j依赖。
  2. 通过反编译查看依赖版本
    通过jd-gui查看hive-exec-2.3.8.jar里包含的slf4j依赖版本

    发现两个版本确实是不一致的,想办法解决这个问题。

解决

  1. 通过maven的依赖覆盖解决这个问题
  2. 通过maven shade插件改名解决这个问题
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.2.4</version>
    <executions>
    <execution>
    <phase>package</phase>
    <goals>
    <goal>shade</goal>
    </goals>
    <configuration>
    <artifactSet>
    <includes>
    <include>*:*</include>
    </includes>
    </artifactSet>
    <relocations>
    <relocation>
    <pattern>org.slf4j..</pattern>
    <shadedPattern>shade.org.slf4j.</shadedPattern>
    </relocation>
    </relocations>
    </configuration>
    </execution>
    </executions>
    </plugin>