Caused by: java.lang.IllegalArgumentException: LoggerFactory is not a Logback LoggerContext but Logb

Caused by: java.lang.IllegalArgumentException: LoggerFactory is not a Logback LoggerContext but Logback is on the classpath. …

问题:

在一次依赖升级中,发生springboot项目本地启动没问题,但是打成war包部署到服务器就会出现这个报错。(springboot默认使用的是logback日志框架)

分析:日志框架之间发生冲突。

排查:

首先定位这个错误信息是在哪打印出来的,拿到这个报错信息全局搜索。发现在如下的地方
Caused by: java.lang.IllegalArgumentException: LoggerFactory is not a Logback LoggerContext but Logb_第1张图片

然后打断点,启动项目,等到断点进入后看到当前的factory实例确实不是logback, 搜索StaticLoggerBinber如下图:
这里因为我已经排查过一次包只搜到了logback-classic依赖中的类,如果你在没有排包之前搜索是能搜到slf4j12的依赖中的这个类的。这样我们就基本知道问题出在哪里了(这里解决的办法就是在maven中exclusion掉冲突的依赖),我们继续往下看,看springboot到底是如何来加载日志框架的。
Caused by: java.lang.IllegalArgumentException: LoggerFactory is not a Logback LoggerContext but Logb_第2张图片

此时我们的断点还没有放开,我们顺着当前Thread的栈帧来查看是怎么一个加载顺序,如下图:
Caused by: java.lang.IllegalArgumentException: LoggerFactory is not a Logback LoggerContext but Logb_第3张图片

我们可以看到springboot的入口在main,而且当前线程的名称也为main,我们注意到程序从启动进入main入口开始,一步步往下执行(springboot的启动是基于springframework的事件机制,从当前线程的方法栈也可以看出来,这里暂不讨论,以后有时间补上),我们看到有个函数叫onApplicationEvent,定位到这个函数后发现调用了onApplicationStartingEvent,这个函数干了什么事呢?我们看下图:
在这里插入图片描述

我们看到这个函数通过当前的类加载器来获取被加载的日志系统,具体的细节如下:
Caused by: java.lang.IllegalArgumentException: LoggerFactory is not a Logback LoggerContext but Logb_第4张图片

至此 我们大概的了解到springboot是如何来加载日志系统 的,问题的原因我们也基本定位到了,在上图中我们能够清楚的看到日志系统类的加载是通过类加载器和类名来获取的,但是在我的项目中不知道什么原因导致加载的日志系统为LogbackLoggingSystem而通过ContextSelector获取到的日志的上下文是别的日志框架导致报错。

我排过一次包之后项目就正常启动,同时将之前排包的地方注销掉打的包也是可以正常运行的,所以问题应该不止这么简单(暂时不会分析jvm加载类的知识,以后会了补上,在此不做臆测)

同时对于网上说的这个问题是因为和slf4j冲突其实是不准确的,因为slf4j是一个针对各种日志框架的简单门面或抽象,所以说这两者冲突是完全不对的,而且在springboot加载日志的源码中我们能证实这一点,如下图:
Caused by: java.lang.IllegalArgumentException: LoggerFactory is not a Logback LoggerContext but Logb_第5张图片

解决:解决的办法因人而异,如果是因为依赖的原因,只需要在pom中排掉冲突的依赖即可。

你可能感兴趣的:(java)