解决在Spring Boot 2.x中升级slf4j至2.x时出现的报错问题
https://gitee.com/qdbp/spring-boot-sfj4j2/
我们有个老项目是spring-boot-2.7.18,近期扫描logback存在漏洞
项目中logback用的是1.2.x,即使升级到目前(25年8月)最新版1.2.13,仍然报3个中危漏洞
再往上升级,就需要同时升级slf4j至2.x,改好后启动项目,就报这个错:
ClassNotFoundException: org.slf4j.impl.StaticLoggerBinder
原因是slf4j对日志实例的发现机制由之前的静态绑定机制改为了SPI机制
而spring-boot-2.7.x的LogbackLoggingSystem中使用了老的类,于是报错了
Exception in thread "main" java.lang.NoClassDefFoundError: org/slf4j/impl/StaticLoggerBinder
at org.springframework.boot.logging.logback.LogbackLoggingSystem.getLoggerContext(LogbackLoggingSystem.java:304)
at org.springframework.boot.logging.logback.LogbackLoggingSystem.beforeInitialize(LogbackLoggingSystem.java:118)
at org.springframework.boot.context.logging.LoggingApplicationListener.onApplicationStartingEvent(LoggingApplicationListener.java:238)
at org.springframework.boot.context.logging.LoggingApplicationListener.onApplicationEvent(LoggingApplicationListener.java:220)
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:178)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:171)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:145)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:133)
at org.springframework.boot.context.event.EventPublishingRunListener.starting(EventPublishingRunListener.java:79)
at org.springframework.boot.SpringApplicationRunListeners.lambda$starting$0(SpringApplicationRunListeners.java:56)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:120)
at org.springframework.boot.SpringApplicationRunListeners.starting(SpringApplicationRunListeners.java:56)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:299)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1300)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1289)
at com.gitee.qdbp.slf4j2.test.Application.main(Application.java:26)
Caused by: java.lang.ClassNotFoundException: org.slf4j.impl.StaticLoggerBinder
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 17 more
SpringBoot中的LoggingSystem主要作用是为logback.xml中的变量读取提供支持
<springProperty scope="context" name="appName" source="spring.application.name"/>
......
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/${appName}.log</file>
......
</appender>
网上提到可以将禁用LoggingSystem,这样虽然能启动项目
但是,上述变量就读取不到了,logback-spring.xml需要改为logback.xml
System.setProperty("org.springframework.boot.logging.LoggingSystem", "none");
SpringApplication.run(Application.class, args);
SpringBoot2.7 霸王硬上弓 Logback1.3 → 不甜但解渴
感谢青石路大帅哥的思路,前因后果非常详实,赞!!!
看了一下spring-boot的LoggingSystem源码
发现可以自己另外实现一个LogbackLoggingSystem
通过META-INF/spring.factories追加一个LoggingSystem的Factory来修改底层实现
对比LogbackLoggingSystem在2.7.18和3.5.4中的不同实现,基本可以将3.5.4的逻辑迁移过来
调用关系图
跑起来可以看到,LoggingSystem的Factory实现已经多了一个,而且Slf4j2LogbackLoggingSystem排在最上面
关键入口在这里
@Order(Ordered.LOWEST_PRECEDENCE - 10000) // 提高优先级
public static class Factory implements LoggingSystemFactory {
// 有LoggerContext且没有StaticLoggerBinder才生效
private static final boolean PRESENT = ClassUtils.isPresent("ch.qos.logback.classic.LoggerContext",
Factory.class.getClassLoader())
&& !ClassUtils.isPresent("org.slf4j.impl.StaticLoggerBinder", Factory.class.getClassLoader());
@Override
public LoggingSystem getLoggingSystem(ClassLoader classLoader) {
if (PRESENT) {
return new Slf4j2LogbackLoggingSystem(classLoader);
}
return null;
}
}
主要是测试项目在加入spring-boot-sfj4j2依赖后能正常启动
不会报错:NoClassDefFoundError: org/slf4j/impl/StaticLoggerBinder
另外测试logback-spring.xml中的appName取值成功
<file>${LOG_HOME}/${appName}.log</file>
在测试项目中:spring-boot-sfj4j2-test-logback
项目启动成功后,在logs文件下应该会有<b>slf4j2-test-logback.log</b>文件
https://repo1.maven.org/maven2/com/gitee/qdbp/spring-boot-sfj4j2/2.7.18/
<dependency>
<groupId>com.gitee.qdbp</groupId>
<artifactId>spring-boot-sfj4j2</artifactId>
<version>2.7.18</version>
</dependency>
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。