Spring AI 2.0 为什么不再直接使用 SLF4J?
在最近发布的 Spring AI 2.0.0-RC1 中,有一项让人有些意外的代码重构:将原本直接调用的 SLF4J 门面替换为了传统的 Commons Logging API (LogFactory)。这很容易让人产生“设计倒退”的疑惑。本文将为你梳理这一改动的真实背景,带你了解 Spring 统一的 spring-jcl 日志门面机制以及其背后的工程考量。
在 Spring AI 2.0.0-RC1 发布说明中,有这样一项变更:
Replace SLF4J with
org.apache.commons.logging.LogFactory.
代码由:
private static final Logger logger =
LoggerFactory.getLogger(MyClass.class);
变成:
private final Log logger =
LogFactory.getLog(getClass());
这很容易让人误以为 Spring AI 从 SLF4J“倒退”到了 Apache Commons Logging。实际情况并非如此。
包名属于 Apache,实现属于 Spring
Log 和 LogFactory 的包名确实是:
org.apache.commons.logging
但在现代 Spring 应用中,这些类通常由 Spring Framework 的 spring-jcl 模块提供,而不是传统的 Apache commons-logging。
可以在 Spring Framework 仓库看到这个独立模块:
也可以在程序中确认类来自哪个 JAR:
System.out.println(
LogFactory.class.getProtectionDomain()
.getCodeSource()
.getLocation()
);
一般会看到:
spring-jcl-*.jar
而不是:
commons-logging-*.jarSpring 什么时候开始使用 spring-jcl?
Spring Framework 很早就使用 Commons Logging API。
真正的变化发生在 Spring Framework 5.0,于 2017 年发布:Spring 开始提供自己的 spring-jcl 兼容实现。
证据可以从 Spring Framework 5.0 的源码和 Maven 构件中看到:
- Spring Framework 5.0.0.RELEASE 的
spring-jcl - Maven Central:
spring-jcl5.0.0.RELEASE - Spring Framework 5.0 发布文档
因此,Spring AI 2.0 并不是创造了一种新的日志方案,只是在向 Spring Framework 已有的规范靠拢。
Spring Boot 不是使用 SLF4J 吗?
更准确地说:
- Spring Boot 内部代码使用 Commons Logging API,由
spring-jcl提供。 - Spring Boot 默认选择 Logback 作为日志实现。
- SLF4J 是其中重要的路由和兼容层。
Spring Boot 官方文档明确说明:
Spring Boot uses Commons Logging for all internal logging but leaves the underlying log implementation open.
同时,使用 Starter 时默认采用 Logback,并负责把 SLF4J、JUL、Commons Logging 等日志统一路由。
典型调用链可以简化为:
Spring Framework / Spring AI
↓
spring-jcl
↓
SLF4J 兼容与路由
↓
Logback
因此,Spring AI 改用 LogFactory 后,Boot 应用最终仍然通常由 Logback 输出日志。
为什么 Spring 不彻底迁移到 SLF4J?
SLF4J 本身没有问题。Spring 没有全面迁移,主要是工程权衡。
收益有限
在 Spring Boot 应用中,各类日志本来就会被统一路由到默认的 Logback。修改 Spring Framework 全部源码,对最终用户几乎没有可见收益。
兼容成本较高
Spring 长期使用 org.apache.commons.logging API。迁移可能影响:
- Framework 内部代码
- Spring 组合项目
- 第三方扩展
- 暴露
Log类型的受保护或公共 API - 已经编译的二进制代码
即使安排在大版本中,这仍是一项成本很高、收益有限的变化。
Framework 与 Boot 的职责不同
Spring Framework 是基础库,允许脱离 Spring Boot 使用,因此需要适应不同日志环境。
Spring Boot 面向最终应用,可以提供更明确的默认组合:
Spring Boot Starter → SLF4J 生态 → Logback
Framework 保留自己的适配层,可以避免直接把 SLF4J 作为内部日志契约。
Spring 可以控制日志发现逻辑
传统 Commons Logging 的运行时发现机制曾带来类加载问题。spring-jcl 保留兼容 API,但实际适配逻辑由 Spring 控制。
这也是它继续使用原包名的原因:兼容旧代码,而不是继续依赖旧实现。
对开发者有什么影响?
对于普通 Spring Boot 应用,基本没有影响:
logging.level.org.springframework.ai=DEBUG
这类配置仍然有效,日志也仍然默认由 Logback 输出。
不要因为看到 org.apache.commons.logging 就主动添加:
<artifactId>commons-logging</artifactId>
传统 commons-logging 与 spring-jcl 提供同名类,放在一起可能产生冲突。
结论
Spring AI 2.0 的变化不是:
SLF4J → 老旧 Commons Logging
而是:
直接使用 SLF4J
↓
改用 Spring 统一的 spring-jcl 门面
↓
运行时仍可进入 SLF4J / Logback
SLF4J 没有什么技术问题。这次调整主要是为了让 Spring AI 与 Spring Framework 和其他 Spring 项目保持一致,同时继续维持日志后端的可替换性和历史兼容性。