SpringBoot 通过
LoggingApplicationListener监听 Spring 上下文生命周期,借助LoggingSystemFactory/LoggingSystem抽象层,在启动阶段自动完成日志框架(Logback / Log4j2 / JUL)的检测与初始化。
相关笔记:SpringBoot 启动流程源码分析 · Spring 术语与缩写速查 · Spring 容器启动流程源码分析
目录
| 章节 | 说明 |
|---|---|
| 整体架构 | 核心组件与职责 |
| 初始化流程 | 启动阶段日志系统的完整触发路径 |
| 源码分析 | 关键类与方法解析 |
| 扩展点 | 如何接入自定义日志框架 |
整体架构
SpringBoot 日志集成由四个层次构成:
| 组件 | 层次 | 职责 |
|---|---|---|
LoggingApplicationListener |
事件触发层 | 监听 Spring 上下文事件,在适当阶段驱动日志系统初始化 |
LoggingSystemFactory |
工厂抽象层 | 定义创建 LoggingSystem 的接口,通过 spring.factories 注册候选实现 |
DelegatingLoggingSystemFactory |
委托选择层 | 按顺序遍历所有候选 Factory,返回第一个可用实现 |
LoggingSystem(及其实现) |
适配执行层 | 封装具体日志框架的初始化与配置加载逻辑 |
SpringBoot 内置三个 LoggingSystem 实现,按类路径优先级依次检测:
| 实现类 | 对应框架 | 检测依据 |
|---|---|---|
LogbackLoggingSystem |
Logback | ch.qos.logback.classic.LoggerContext 存在于类路径 |
Log4J2LoggingSystem |
Log4j2 | org.apache.logging.log4j.core.impl.Log4jContextFactory 存在于类路径 |
JavaLoggingSystem |
JUL | 兜底实现,始终可用 |
优先级规则:三个 Factory 按
spring.factories声明顺序依次尝试,第一个返回非 null 的实现生效。默认 starter 引入 Logback,故 Logback 优先。
初始化流程
源码分析
关键类一览
| 类名 | 所在包 | 职责 |
|---|---|---|
LoggingApplicationListener |
o.s.boot.context.logging |
事件监听入口 |
LoggingSystemFactory |
o.s.boot.logging |
工厂接口 |
DelegatingLoggingSystemFactory |
o.s.boot.logging |
委托选择策略 |
LogbackLoggingSystem |
o.s.boot.logging.logback |
Logback 适配 |
Log4J2LoggingSystem |
o.s.boot.logging.log4j2 |
Log4j2 适配 |
spring.factories 注册
LoggingApplicationListener 和各 LoggingSystemFactory 均通过 spring.factories 注册:
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.context.logging.LoggingApplicationListener
# Logging Systems(按优先级排列)
org.springframework.boot.logging.LoggingSystemFactory=\
org.springframework.boot.logging.logback.LogbackLoggingSystem.Factory,\
org.springframework.boot.logging.log4j2.Log4J2LoggingSystem.Factory,\
org.springframework.boot.logging.java.JavaLoggingSystem.Factory
LoggingSystemFactory:工厂接口
public interface LoggingSystemFactory {
// 根据类加载器判断当前环境是否支持该日志框架,返回 null 表示不支持
LoggingSystem getLoggingSystem(ClassLoader classLoader);
// 通过 spring.factories 加载所有候选 Factory,委托给 DelegatingLoggingSystemFactory
static LoggingSystemFactory fromSpringFactories() {
return new DelegatingLoggingSystemFactory(
(classLoader) -> SpringFactoriesLoader.loadFactories(
LoggingSystemFactory.class, classLoader));
}
}
DelegatingLoggingSystemFactory:选择策略
class DelegatingLoggingSystemFactory implements LoggingSystemFactory {
private final Function<ClassLoader, List<LoggingSystemFactory>> delegates;
@Override
public LoggingSystem getLoggingSystem(ClassLoader classLoader) {
List<LoggingSystemFactory> delegates = this.delegates.apply(classLoader);
if (delegates != null) {
for (LoggingSystemFactory delegate : delegates) {
LoggingSystem loggingSystem = delegate.getLoggingSystem(classLoader);
if (loggingSystem != null) {
return loggingSystem; // 返回第一个非 null 实现,后续 Factory 不再尝试
}
}
}
return null;
}
}
Log4J2LoggingSystem.Factory:类路径探测示例
@Order(Ordered.LOWEST_PRECEDENCE)
public static class Factory implements LoggingSystemFactory {
// 静态检测:类加载时一次性判断 Log4j2 是否在类路径中
private static final boolean PRESENT = ClassUtils.isPresent(
"org.apache.logging.log4j.core.impl.Log4jContextFactory",
Factory.class.getClassLoader());
@Override
public LoggingSystem getLoggingSystem(ClassLoader classLoader) {
if (PRESENT) {
return new Log4J2LoggingSystem(classLoader);
}
return null;
}
}
Log4J2LoggingSystem:加载配置文件
// Log4J2LoggingSystem#loadConfiguration
protected void loadConfiguration(String location, LogFile logFile) {
Assert.notNull(location, "Location must not be null");
try {
LoggerContext ctx = getLoggerContext();
URL url = ResourceUtils.getURL(location);
ConfigurationSource source = getConfigurationSource(url);
// 通过 LoggerContext#start 将新配置热应用到运行中的 Log4j2 实例
ctx.start(ConfigurationFactory.getInstance().getConfiguration(ctx, source));
}
catch (Exception ex) {
throw new IllegalStateException(
"Could not initialize Log4J2 logging from " + location, ex);
}
}
扩展点
如需接入自定义日志框架,只需三步:
- 实现
LoggingSystemFactory,在getLoggingSystem()中检测自定义框架类是否存在 - 实现
LoggingSystem,封装框架的初始化与配置加载逻辑 - 在
src/main/resources/META-INF/spring.factories中注册:
org.springframework.boot.logging.LoggingSystemFactory=\
com.example.MyLoggingSystemFactory
⚠️ Factory 的注册顺序即优先级顺序。若要覆盖默认 Logback,需将自定义 Factory 排在
LogbackLoggingSystem.Factory前面。
参考资料
- Spring Boot 源码:
org.springframework.boot.context.logging.LoggingApplicationListener- Spring Boot 源码:
org.springframework.boot.logging.LoggingSystemFactory- 《Spring Boot Reference Documentation》— Features › Logging
评论 (0)
发表评论