首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >解决在Spring Boot 2.x中升级slf4j至2.x时出现的报错问题

解决在Spring Boot 2.x中升级slf4j至2.x时出现的报错问题

原创
作者头像
zhaohuihua
发布2025-08-15 09:42:40
发布2025-08-15 09:42:40
2150
举报

介绍

解决在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中使用了老的类,于是报错了

代码语言:txt
复制
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中的变量读取提供支持

代码语言: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

代码语言:java
复制
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排在最上面

工厂类实例
工厂类实例

关键入口在这里

代码语言:java
复制
@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>文件

Maven依赖

https://repo1.maven.org/maven2/com/gitee/qdbp/spring-boot-sfj4j2/2.7.18/

代码语言:xml
复制
<dependency>
	<groupId>com.gitee.qdbp</groupId>
	<artifactId>spring-boot-sfj4j2</artifactId>
	<version>2.7.18</version>
</dependency>

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 介绍
  • 问题原因
  • 问题分析
  • 代码实现
  • 日志测试
  • Maven依赖
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档