• 近期将进行后台系统升级,如有访问不畅,请稍后再试!
  • 极客文库-知识库上线!
  • 极客文库小编@勤劳的小蚂蚁,为您推荐每日资讯,欢迎关注!
  • 每日更新优质编程文章!
  • 更多功能模块开发中。。。

Maven 中 jar 包冲突的排查经验谈

在一次项目启动中,遇到了一个报错

“java.lang.NoSuchMethodError: org.slf4j.spi.LocationAwareLogger.log”

简单 Google 一下,是 jar 包冲突的问题。

按照网上的思路,首先查看 mvn 中冲突的包

使用命令:

mvn dependency:tree -Dverbose | grep “omitted for conflict with”

通常上面的显示的信息非常多,如果已经明确了冲突的包,比如本场景下是 log4j/slf4j

使用命令:

mvn dependency:tree -Dverbose -Dincludes=log4j:log4j

具体查看 pom 文件,修改冲突的包。

把一些明显的冲突修改了以后,再次启动,仍然报错,报错信息变了:

Exception in thread “main” java.lang.IllegalAccessError: tried to access field
org.slf4j.impl.StaticLoggerBinder.SINGLETON from class org.slf4j.LoggerFactory
   at org.slf4j.LoggerFactory.<clinit>(LoggerFactory.java:60)

通过 Google 找到原因如下:

是由于低版本的 slf4j 的 bug,具体原因查看这个 Blog,按理说找到对应的 pom 配置,升级下 version 就可以了。

可是我将 pom 中的 slf4j-api 和 slf4j-log4j12 升级到 1.7+,仍然报同样的错误。

查看本地 M2_REPO,将低版本的 slf4j-api 和 slf4j-log4j12 删除,仍然报同样的错。

开始怀疑是从其他 jar 包中加载了 LoggerFactory。

如何查看一个类加载的来源信息呢?

VM 的-verbose 参数解决了这个问题

-verbose[:class|gc|jni] 在输出设备上显示虚拟机运行信息。

在程序运行的时候有多少类被加载!你可以用 verbose:class 来监视,在命令行输入 java -verbose:class XXX (XXX 为程序名)你会在控制台看到加载的类的情况。

verbose 和 verbose:class 含义相同,输出虚拟机装入的类的信息,显示的信息格式如下:

[Opened D:Javajdk1.6.0_25jrelibrt.jar]
[Loaded java.lang.Object from D:Javajdk1.6.0_25jrelibrt.jar]
[Loaded java.io.Serializable from D:Javajdk1.6.0_25jrelibrt.jar]
[Loaded java.lang.Comparable from D:Javajdk1.6.0_25jrelibrt.jar]
[Loaded java.lang.CharSequence from D:Javajdk1.6.0_25jrelibrt.jar]
[Loaded java.lang.String from D:Javajdk1.6.0_25jrelibrt.jar]
[Loaded java.lang.reflect.GenericDeclaration from D:Javajdk1.6.0_25jrelibrt.jar]
[Loaded java.lang.reflect.Type from D:Javajdk1.6.0_25jrelibrt.jar]
[Loaded java.lang.reflect.AnnotatedElement from D:Javajdk1.6.0_25jrelibrt.jar]
[Loaded java.lang.Class from D:Javajdk1.6.0_25jrelibrt.jar]
[Loaded java.lang.Cloneable from D:Javajdk1.6.0_25jrelibrt.jar]
[Loaded java.lang.ClassLoader from D:Javajdk1.6.0_25jrelibrt.jar]
[Loaded java.lang.System from D:Javajdk1.6.0_25jrelibrt.jar]
[Loaded java.lang.Throwable from D:Javajdk1.6.0_25jrelibrt.jar]

当虚拟机报告类找不到或类冲突时可用此参数来诊断来查看虚拟机从装入类的情况。

在本场景排查问题时,发现类 LoggerFactory 加载来源于 com.springsource.slf4j.api,将对应的 jar 包移除,问题解决。

值得注意的是,-verbose 参数在 jvm 故障诊断时同样有着重要的作用

java –verbose:gc

在虚拟机发生内存回收时在输出设备显示信息,格式如下:

[Full GC 256K->160K(124096K), 0.0042708 secs]

该参数用来监视虚拟机内存回收的情况。

public class JvmVerbose {
/**
* JVM -verbose[:class|gc|jni] 参数测试
* @param args
*/
   public static void main(String[] args) {
        JvmVerbose jvmVerbose = new JvmVerbose();
        System.gc();
   }
}

在这个例子中,一个新的对象被创建,由于它没有使用,所以该对象迅速地变为可达,程序编译后,执行命令:

java -verbose:gc JvmVerbose

结果:

[GC 647K->256K(124096K), 0.0274253 secs]
[Full GC 256K->160K(124096K), 0.0042708 secs]

箭头前后的数据 256K 和 160K 分别表示垃圾收集 GC 前后所有存活对象使用的内存容量,说明有 256K-160K=96K 的对象容量被回收,括号内的数据 124096K 为堆内存的总容量,收集所需要的时间是 0.0042708 秒(这个时间在每次执行的时候会有所不同)。

java –verbose:jni

-verbose:jni 输出 native 方法调用的相关情况,一般用于诊断 jni 调用错误信息。

在虚拟机调用 native 方法时输出设备显示信息,格式如下:

[Dynamic-linking native method java.lang.Object.registerNatives … JNI]

该参数用来监视虚拟机调用本地方法的情况,在发生 jni 错误时可为诊断提供便利。

Reference:



丨极客文库, 版权所有丨如未注明 , 均为原创丨
本网站采用知识共享署名-非商业性使用-相同方式共享 3.0 中国大陆许可协议进行授权
转载请注明原文链接:Maven 中 jar 包冲突的排查经验谈
喜欢 (0)
[247507792@qq.com]
分享 (0)
勤劳的小蚂蚁
关于作者:
温馨提示:本文来源于网络,转载文章皆标明了出处,如果您发现侵权文章,请及时向站长反馈删除。

欢迎 注册账号 登录 发表评论!

  • 精品技术教程
  • 编程资源分享
  • 问答交流社区
  • 极客文库知识库

客服QQ


QQ:2248886839


工作时间:09:00-23:00