目录
正在加载目录…
专栏文章
专栏文章
SpringBoot 系列
1. Spring Boot 启动:从 main 到容器刷新 2. Spring Boot 日志:配置加载与 Logback 集成 3. Spring Boot 自动装配:条件注解、SPI 与 Starter

Spring Boot 日志:配置加载与 Logback 集成

发布于 2026-05-26 09:43 · 最后编辑于 2026-07-31 15:53 · 字数 1,842 👁 69 次阅读

SpringBoot 通过 LoggingApplicationListener 监听 Spring 上下文生命周期,借助 LoggingSystemFactory / LoggingSystem 抽象层,在启动阶段自动完成日志框架(Logback / Log4j2 / JUL)的检测与初始化。

相关笔记SpringBoot 启动流程源码分析 · ../00 Spring 术语与缩写速查 · ../01 Spring-Framework/01 Spring 容器启动流程源码分析

目录

章节说明
整体架构核心组件与职责
初始化流程启动阶段日志系统的完整触发路径
源码分析关键类与方法解析
扩展点如何接入自定义日志框架

整体架构

SpringBoot 日志集成由四个层次构成:

组件层次职责
LoggingApplicationListener事件触发层监听 Spring 上下文事件,在适当阶段驱动日志系统初始化
LoggingSystemFactory工厂抽象层定义创建 LoggingSystem 的接口,通过 spring.factories 注册候选实现
DelegatingLoggingSystemFactory委托选择层按顺序遍历所有候选 Factory,返回第一个可用实现
LoggingSystem(及其实现)适配执行层封装具体日志框架的初始化与配置加载逻辑

SpringBoot 内置三个 LoggingSystem 实现,按类路径优先级依次检测:

实现类对应框架检测依据
LogbackLoggingSystemLogbackch.qos.logback.classic.LoggerContext 存在于类路径
Log4J2LoggingSystemLog4j2org.apache.logging.log4j.core.impl.Log4jContextFactory 存在于类路径
JavaLoggingSystemJUL兜底实现,始终可用

优先级规则:三个 Factory 按 spring.factories 声明顺序依次尝试,第一个返回非 null 的实现生效。默认 starter 引入 Logback,故 Logback 优先。

初始化流程

../../../assets/02 SpringBoot 日志集成原理/file 20260605123838390

源码分析

关键类一览

类名所在包职责
LoggingApplicationListenero.s.boot.context.logging事件监听入口
LoggingSystemFactoryo.s.boot.logging工厂接口
DelegatingLoggingSystemFactoryo.s.boot.logging委托选择策略
LogbackLoggingSystemo.s.boot.logging.logbackLogback 适配
Log4J2LoggingSystemo.s.boot.logging.log4j2Log4j2 适配

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);
    }
}

扩展点

如需接入自定义日志框架,只需三步:

  1. 实现 LoggingSystemFactory,在 getLoggingSystem() 中检测自定义框架类是否存在
  2. 实现 LoggingSystem,封装框架的初始化与配置加载逻辑
  3. 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)

暂无评论,来留下第一条吧。
登录注册 后才能发表评论