slf4j-api ------ 日志门面(核心)
是什么
-
slf4j-api是 SLF4J 的核心接口包 -
只定义接口,不包含任何具体日志实现
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
作用
-
提供统一的日志 API
-
让业务代码不依赖具体日志实现(Logback / Log4j2 / JUL 等)
-
实现 面向接口编程
特点
| 特性 | 说明 |
|---|---|
| 是否包含实现 | ❌ 否 |
| 是否可单独使用 | ❌ 否 |
| 是否必须引入 | ✅ 是 |
所有 SLF4J 项目都必须引入
*-over-slf4j ------ "日志桥接器"(偷天换日)
这类 jar 的共同点是:
把别的日志框架的调用,偷偷转发给 SLF4J
它们通常用于 遗留系统 / 第三方依赖。
jul-to-slf4j(Java Util Logging → SLF4J)
解决什么问题
-
JDK 自带的日志:
java.util.logging(JUL) -
很多 JDK 内部或老代码在用
作用
- 将
java.util.logging.Logger的输出桥接到 SLF4J
使用方式
需要显式安装桥接 handler
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
特点
| 项目 | 说明 |
|---|---|
| 自动生效 | ❌ 否 |
| 性能损耗 | ✅ 有一定 |
| 是否常用 | ✅ 中等 |
常见于 JDK 原生日志较多的系统
一句话总结
| 组件 | 一句话解释 |
|---|---|
| slf4j-api | 日志门面接口 |
| jcl-over-slf4j | JCL → SLF4J |
| jul-to-slf4j | JUL → SLF4J |
| log4j-over-slf4j | Log4j1 → SLF4J |
除了slf4j-api,都是转发的作用,为什么有的用to,有的用over呢?
| 命名 | 本质区别 |
|---|---|
xxx-to-slf4j |
"转接":从 A 转到 SLF4J(通常较轻量) |
xxx-over-slf4j |
"覆盖":用同名类直接盖掉原来的实现 |
为什么 JUL 用 to,而 JCL / Log4j 用 over?
jul-to-slf4j------ 为什么是 to?
原因 1:JUL 无法被"覆盖"
-
java.util.logging是 JDK 内置包 -
你不能在 classpath 里放一个:
java.util.logging.Logger会被 JVM 拒绝(安全管理 + 类加载机制)
原因 2:只能通过 Handler 转接
-
SLF4J 的做法是:
-
给 JUL 注册一个
Handler -
在 Handler 里把日志事件转发给 SLF4J
SLF4JBridgeHandler.install();
-
本质是:
JUL → Handler → SLF4J
所以是 to(转过去)
jcl-over-slf4j/ log4j-over-slf4j------ 为什么是 over?
原因 1:这些日志框架是"外部 jar"
-
Apache Commons Logging
-
Log4j 1.x
它们都在 应用 classpath 中,可以被覆盖。
原因 2:SLF4J 使用了"类级覆盖"
以 jcl-over-slf4j为例:
org.apache.commons.logging.Log
org.apache.commons.logging.LogFactory
SLF4J 提供了一个 一模一样的包名 + 类名
JVM 类加载时:
-
先加载到的是 SLF4J 的版本
-
原有实现直接"被架空"
本质是:
旧日志 API → 同名类 → SLF4J
所以是 over(盖在上面)
从"侵入性"理解 to vs over
| 维度 | to | over |
|---|---|---|
| 是否替换原有类 | ❌ 否 | ✅ 是 |
| 是否修改原框架行为 | ❌ 很少 | ✅ 完全接管 |
| 是否依赖类加载顺序 | ❌ 否 | ✅ 是 |
| 风险 | 低 | 中 |
| 典型代表 | jul-to-slf4j | jcl-over-slf4j log4j-over-slf4j |
判断该用哪个
问自己一个问题:
这个日志框架的类,我能自己在 classpath 里"重写"吗?
-
能 →
xxx-over-slf4j -
不能 →
xxx-to-slf4j