点击上方“码农突围”,马上关注 这里是码农充电第一站,回复“666”,获取一份专属大礼包 真爱,请设置“星标”或点个“在看”
起因
ClassCastException
报错原因
Class path contains multiple SLF4J binding
23-May-2019 16:04:25.300 INFO [localhost-startStop-1] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/home/admin/xxx/WEB-INF/lib/slf4j-log4j12-1.6.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/home/admin/xxx/WEB-INF/lib/logback-classic-1.1.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]
报错原因
org.slf4j.impl.Log4jLoggerFactory cannot be cast to ch.qos.logback.classic.LoggerContext
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cn.com.xxx.framework.log.integration.LogbackInitializer#0' defined in class path resource [spring/spring-log-init.xml]: Invocation of init method failed; nested exception is java.lang.ClassCastException: org.slf4j.impl.Log4jLoggerFactory cannot be cast to ch.qos.logback.classic.LoggerContext
...
Caused by: java.lang.ClassCastException: org.slf4j.impl.Log4jLoggerFactory cannot be cast to ch.qos.logback.classic.LoggerContext
# 出问题的加载地方
at ch.qos.logback.ext.spring.LogbackConfigurer.initLogging(LogbackConfigurer.java:72)
at cn.com.xxx.framework.log.integration.LogbackInitializer.init(LogbackInitializer.java:49)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(AbstractAutowireCapableBeanFactory.java:1706)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1645)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
... 26 more
23-May-2019 15:59:12.398 SEVERE [localhost-startStop-1] org.apache.catalina.core.StandardContext.startInternal One or more listeners failed to start. Full details will be found in the appropriate container log file
查看报错代码
public static void initLogging(String location) throws FileNotFoundException, JoranException {
String resolvedLocation = SystemPropertyUtils.resolvePlaceholders(location);
URL url = ResourceUtils.getURL(resolvedLocation);
LoggerContext loggerContext = (LoggerContext)StaticLoggerBinder.getSingleton().getLoggerFactory();
loggerContext.reset();
new ContextInitializer(loggerContext).configureByResource(url);
}
StaticLoggerBinder.getSingleton().getLoggerFactory()
获取 logger 上下文这段代码报错了,通过仔细定位,发现了有两个 StaticLoggerBinder
类logback
包,而不是 slf4j-log4j12
包,所以需要排除掉 slf4j-log4j12
依赖。解决方法
Maven Helper
Jump To Source(跳转到源文件处)
Exclude(排除掉)
Exclude
,就能看到 pom 文件中,这个依赖就被排除掉了<dependency>
<groupId>cn.com.xxx</groupId>
<artifactId>framework-conf-client</artifactId>
<version>${xqy.framework.version}</version>
<exclusions>
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
思考
jdk 版本
tomcat 版本
类加载机制
第三方 jar 互相依赖
类加载机制
App ClassLoader
应用加载器进行加载,它不会自己先去加载它,而是通过 Extension ClassLoader
扩展类加载器进行加载(其中扩展类加载器又会去找 Bootstrap ClassLoader
启动类加载器进行加载),只有父加载器无法加载情况下,才会让下级加载器进行加载。ClassLoader
ClassLoader
类,可以对此有所了解。protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
// 首先,检查 class 是否已经被加载
Class<?> c = findLoadedClass(name);
if (c == null) {
// 如果没有被加载
long t0 = System.nanoTime();
try {
if (parent != null) {
// 寻找 parent 加载器
c = parent.loadClass(name, false);
} else {
// 如果父加载器不存在,则委托给启动类加载器加载
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
// 如果仍然无法加载,才会尝试自身加载
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
类加载顺序
org.slf4j
包的 org.slf4j.impl.StaticLoggerBinder
,同名的 ch.qos.logback
包下的 StaticLoggerBinder
类没有被加载查看加载顺序
-verbose
参数或者 -XX:+TraceClassLoading
[Loaded java.lang.CloneNotSupportedException from /Users/jingqi/.jrebel/bootcache/jrebel-bootstrap-89f567048120ef32b965233b5ba2f7ca.jar]
[Loaded java.lang.Thread$State from /Users/jingqi/.jrebel/bootcache/jrebel-bootstrap-89f567048120ef32b965233b5ba2f7ca.jar]
[Loaded java.util.TreeMap$NavigableSubMap from /Users/jingqi/.jrebel/bootcache/jrebel-bootstrap-89f567048120ef32b965233b5ba2f7ca.jar]
[Loaded java.util.TreeMap$AscendingSubMap from /Users/jingqi/.jrebel/bootcache/jrebel-bootstrap-89f567048120ef32b965233b5ba2f7ca.jar]
[Loaded java.util.TreeMap$NavigableSubMap$EntrySetView from /Users/jingqi/.jrebel/bootcache/jrebel-bootstrap-89f567048120ef32b965233b5ba2f7ca.jar]
[Loaded java.util.TreeMap$AscendingSubMap$AscendingEntrySetView from /Users/jingqi/.jrebel/bootcache/jrebel-bootstrap-89f567048120ef32b965233b5ba2f7ca.jar]
[Loaded java.util.TreeMap$NavigableSubMap$SubMapIterator from /Users/jingqi/.jrebel/bootcache/jrebel-bootstrap-89f567048120ef32b965233b5ba2f7ca.jar]
[Loaded java.util.TreeMap$NavigableSubMap$SubMapEntryIterator from /Users/jingqi/.jrebel/bootcache/jrebel-bootstrap-89f567048120ef32b965233b5ba2f7ca.jar]
ch.qos.logback
的 StaticLoggerBinder
类,然后后面的 org.slf4j
包下的同名类就没有被加载。inode
是否是问题的原因,我做了以下测试:inode 测试加载顺序
本地 Tomcat8 测试(正常启动)
catalina.sh
脚本中加入类加载打印参数 -XX:+TraceClassLoading
# Register custom URL handlers
# Do this here so custom URL handles (specifically 'war:...') can be used in the security policy
JAVA_OPTS="$JAVA_OPTS -XX:+TraceClassLoading"
catalina.out
输入日志,发现先加载的是 logback 包中 StaticLoggerBinder
WEB-INF/lib
下比较 inode 大小(正常解压和启动 logback < slf4j)ll -i logback-classic-1.1.3.jar slf4j-log4j12-1.6.1.jar
34153162 -rw-r----- 1 jingqi staff 274K 8 1 2018 logback-classic-1.1.3.jar
34153180 -rw-r----- 1 jingqi staff 9.5K 10 17 2018 slf4j-log4j12-1.6.1.jar
本地 Tomcat8 测试(删包,先添加 slf4j,后添加 logback)
清理掉 catalina.out
重新上传包
比较 inode 大小
重新启动,查看类加载日志
# ll -i logback-classic-1.1.3.jar slf4j-log4j12-1.6.1.jar
34162396 -rw-r--r-- 1 jingqi staff 274K 8 1 2018 logback-classic-1.1.3.jar
34162361 -rw-r--r-- 1 jingqi staff 9.5K 10 17 2018 slf4j-log4j12-1.6.1.jar
catalina.out
日志,发现类加载顺序与之前的一致,应用也能正常启动,所以本地开发无法复现 =-=在 uat 环境服务器测试
WEB-INF/lib
路径下,先将这两个包删掉,尝试有不同的上传顺序,模拟 tomcat 解压 war 包[admin@uat-96-0-248 lib]$ rm logback-classic-1.1.3.jar slf4j-log4j12-1.6.1.jar
[admin@uat-96-0-248 lib]$ rz
[admin@uat-96-0-248 lib]$ # Received /Users/jingqi/Downloads/slf4j-log4j12-1.6.1.jar
[admin@uat-96-0-248 lib]$ rz
[admin@uat-96-0-248 lib]$ # Received /Users/jingqi/Downloads/logback-classic-1.1.3.jar
# 第一次上传顺序 1、slf4j-log4j12-1.6.1.jar 2、logback-classic-1.1.3.jar
# inode 比较:slf4j < logback
[admin@uat-96-0-248 lib]$ ll -i logback-classic-1.1.3.jar slf4j-log4j12-1.6.1.jar
396731 -rw-r--r-- 1 admin admin 280928 8月 1 2018 logback-classic-1.1.3.jar
394075 -rw-r--r-- 1 admin admin 9753 10月 17 2018 slf4j-log4j12-1.6.1.jar
[admin@uat-96-0-248 lib]$ rm logback-classic-1.1.3.jar slf4j-log4j12-1.6.1.jar
[admin@uat-96-0-248 lib]$ rz
[admin@uat-96-0-248 lib]$ # Received /Users/jingqi/Downloads/logback-classic-1.1.3.jar
[admin@uat-96-0-248 lib]$ rz
[admin@uat-96-0-248 lib]$ # Received /Users/jingqi/Downloads/slf4j-log4j12-1.6.1.jar
# 第二次上传顺序 1、logback-classic-1.1.3.jar 2、slf4j-log4j12-1.6.1.jar
# inode 比较:logback < slf4j
[admin@uat-96-0-248 lib]$ ll -i logback-classic-1.1.3.jar slf4j-log4j12-1.6.1.jar
394075 -rw-r--r-- 1 admin admin 280928 8月 1 2018 logback-classic-1.1.3.jar
396731 -rw-r--r-- 1 admin admin 9753 10月 17 2018 slf4j-log4j12-1.6.1.jar
inode
两者的大小,都是先加载了 slf4j
包的类,导致启动报错测试结束
[admin@uat-96-0-248 lib]$ cat /proc/version
Linux version 3.10.0-514.26.2.el7.x86_64 (builder@kbuilder.dev.centos.org) (gcc version 4.8.5 20150623 (Red Hat 4.8.5-11) (GCC) ) #1 SMP Tue Jul 4 15:04:05 UTC 2017
# jdk 和 tomcat 版本
Server version: Apache Tomcat/8.5.34
Server built: Sep 4 2018 22:28:22 UTC
Server number: 8.5.34.0
OS Name: Linux
OS Version: 3.10.0-514.26.2.el7.x86_64
Architecture: amd64
JVM Version: 1.8.0_192-b12
JVM Vendor: Oracle Corporation
总结
冲突提示信息
java.lang.ClassNotFoundException:类型转换错误,这个报错跟我这次遇到的一样,本应该引入的是
logback
包的类,但是实际引入的是slf4j
下的同名类,导致类型转换错误java.lang.NoSuchMethodError:找不到特定方法,如果有两个同名的包但是不同版本,例如 xxx-1.1和 xxx-1.2包同时存在,先加载了 1.1 版本的类,但是 1.2 版本中才提供了新方法,导致提示找不到特定方法
java.lang.NoClassDefFoundError,java.lang.LinkageError
排查思路
catalina.sh
堆栈信息,找到有问题的类Maven Helper
插件找出冲突的依赖,确定项目需要的 jar 包,Exclude
掉不需要的依赖。提前预防
maven-enforcer-plugin
WAR
包上传到生产环境,例如我们有一台 UAT 服务器,与生产环境一样配置,提前测试,暴露风险和解决问题~参考资料
https://blog.csdn.net/u011372108/article/details/83824274 https://blog.csdn.net/u014634338/article/details/81434327 https://blog.csdn.net/hnzmdpan/article/details/78637635 https://blog.csdn.net/chufuying3/article/details/47007595 https://www.cnblogs.com/saaav/p/7716179.html https://my.oschina.net/u/3386233/blog/1476822 http://www.voidcn.com/article/p-qncymgza-brh.html https://docs.oracle.com/javase/7/docs/technotes/tools/solaris/classpath.html
最近有有不少老铁在后台留言说,想进大厂,但是算法不好。最近我整理了一份刷题实录,这份刷题实录,也让我进了心仪的大厂。现在开放分享给大家。希望对大家有所帮助。 任何的算法题,如同写作文一样,都有一些模板可以套用的。比如面试常考的DP(动态规划),难的是一些关键点是否能想清楚。比如你能写出动态转移方程,这题基本上就可以AC了。
整个刷题实录内容,包括 双子针、动态规划、二分查找、贪心算法、深度优先搜索、字符串、递归、字典树、排序、链表等相关专题内容。图文并茂,附有刷题答案源码。 刷题任务的题目,是根据题目的类型来汇总的,总结了八个类别,每个类别下面也总结了5个左右的题型,帮助大家分门别类的突破,所以刷起来相对会更有重点和针对性。如果从头到尾的刷,每周按顺序刷42题,很容易让自己坚持不下来,也会觉得很枯燥。所以在制定计划的时候可以让这个计划变得更“有趣"和针对性,让它看起来更容易实现一点,才会更容易坚持。 目前上述内容已打包成完整电子书,具体获取方式如下:
扫描关注 程序猿进阶 公众号;
在 程序猿进阶 公众号后台回复关键词「9999」获取下载地址。
扫描关注,回复"9999"即可下载 最近热文
• 别瞎学了,这几门语言要被淘汰了! • 突发!继22岁拼多多女员工猝死后,又一悲剧:拼多多员工家中跳楼自杀!公司紧急通告! • 我酸了!又是别人家公司!百度新年发 U 奖金鼓励员工 • 外卖小哥凌晨送餐被小区保安打死,都是底层为什么下手这么狠! • 卸载Navicat!操作所有的数据库靠它就够了
在这里,我为大家准备了一份2020年最新最全的《Java面试题及答案V3.0》,这套电子书涵盖了诸多后端技术栈的面试题和答案,相信可以帮助大家在最短的时间内复习Java后端的大多数面试题,从而拿到自己心仪的offer。 截了张图,大家可以仔细查看左边的菜单栏,覆盖的知识面真的很广,而且质量都很不错。 资料获取方法
扫描下方二维码
后台回复关键词:Java核心整理
明天见(。・ω・。)