SpringBoot
的日志系统是在监听器中加载的。
SpringApplication
的实例方法run
,第298行。
listeners.starting(bootstrapContext, this.mainApplicationClass);
最终触发了监听器LoggingApplicationListener
具体方法逻辑
private void onApplicationStartingEvent(ApplicationStartingEvent event) {this.loggingSystem = LoggingSystem.get(event.getSpringApplication().getClassLoader());this.loggingSystem.beforeInitialize();
}
public static final String SYSTEM_PROPERTY = LoggingSystem.class.getName();
private static final LoggingSystemFactory SYSTEM_FACTORY = LoggingSystemFactory.fromSpringFactories();
public static LoggingSystem get(ClassLoader classLoader) {String loggingSystemClassName = System.getProperty(SYSTEM_PROPERTY);if (StringUtils.hasLength(loggingSystemClassName)) {if (NONE.equals(loggingSystemClassName)) {return new NoOpLoggingSystem();}return get(classLoader, loggingSystemClassName);}LoggingSystem loggingSystem = SYSTEM_FACTORY.getLoggingSystem(classLoader);Assert.state(loggingSystem != null, "No suitable logging system located");return loggingSystem;
}
先从环境变量中获取日志配置。
如果有,就用这个全限定类名作为日志系统实例化这个日志系统。
这个类必须是LoggingSystem的子类,否则会报异常。如-Dorg.springframework.boot.logging.LoggingSystem=xxx.xx.xx.XxxLogSystem
如果没有,则从类路径中寻找LoggingSystemFactory
的实现类
static LoggingSystemFactory fromSpringFactories() {return new DelegatingLoggingSystemFactory((classLoader) -> SpringFactoriesLoader.loadFactories(LoggingSystemFactory.class, classLoader));
}
LoggingSystemFactory
的实现类有
# 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
加载后排序,三个类都是被Order注解的
日志系统 | Order |
---|---|
LogbackLoggingSystem.Factory | Integer.MAX_VALUE |
LogbackLoggingSystem.Factory | Integer.MAX_VALUE |
LogbackLoggingSystem.Factory | Integer.MAX_VALUE |
最后顺序是 |
- LogbackLoggingSystem.Factory
- Log4J2LoggingSystem.Factory
- JavaLoggingSystem.Factory
之后在DelegatingLoggingSystemFactory
的getLoggingSystem
方法中获取日志系统。
@Override
public LoggingSystem getLoggingSystem(ClassLoader classLoader) {List<LoggingSystemFactory> delegates = (this.delegates != null) ? this.delegates.apply(classLoader) : null;if (delegates != null) {for (LoggingSystemFactory delegate : delegates) {LoggingSystem loggingSystem = delegate.getLoggingSystem(classLoader);if (loggingSystem != null) {return loggingSystem;}}}return null;
}
从这里可以看出,三个日志系统的优先级顺序:logback
> log4j2
> java log
LoggingSystemFactory.Factory
@Order(Ordered.LOWEST_PRECEDENCE)
public static class Factory implements LoggingSystemFactory {private static final boolean PRESENT = ClassUtils.isPresent("ch.qos.logback.classic.LoggerContext",Factory.class.getClassLoader());@Overridepublic LoggingSystem getLoggingSystem(ClassLoader classLoader) {if (PRESENT) {return new LogbackLoggingSystem(classLoader);}return null;}}
判断类路径中是否有ch.qos.logback.classic.LoggerContext
,有的话,就创建一个LogbackLoggingSystem
对象返回。
默认返回null。
Log4J2LoggingSystem.Factory
@Order(Ordered.LOWEST_PRECEDENCE)
public static class Factory implements LoggingSystemFactory {private static final boolean PRESENT = ClassUtils.isPresent("org.apache.logging.log4j.core.impl.Log4jContextFactory", Factory.class.getClassLoader());@Overridepublic LoggingSystem getLoggingSystem(ClassLoader classLoader) {if (PRESENT) {return new Log4J2LoggingSystem(classLoader);}return null;}}
判断类路径中是否有org.apache.logging.log4j.core.impl.Log4jContextFactory
,如果有,就实例化一个Log4J2LoggingSystem
对象
默认返回null。
JavaLoggingSystem.Factory
@Order(Ordered.LOWEST_PRECEDENCE)
public static class Factory implements LoggingSystemFactory {private static final boolean PRESENT = ClassUtils.isPresent("java.util.logging.LogManager",Factory.class.getClassLoader());@Overridepublic LoggingSystem getLoggingSystem(ClassLoader classLoader) {if (PRESENT) {return new JavaLoggingSystem(classLoader);}return null;}}
判断路径中是否存在java.util.logging.LogManager
,如果存在,就实例化一个JavaLoggingSystem
类。
默认返回null。
不出异常的话,最后总会得到一个日志系统。
然后调用日志系统的beforeInitialize
方法。
初始化
LogbackLoggingSystem
@Override
public void beforeInitialize() {LoggerContext loggerContext = getLoggerContext();if (isAlreadyInitialized(loggerContext)) {return;}super.beforeInitialize();loggerContext.getTurboFilterList().add(FILTER);
}
private LoggerContext getLoggerContext() {ILoggerFactory factory = StaticLoggerBinder.getSingleton().getLoggerFactory();Assert.isInstanceOf(LoggerContext.class, factory,() -> String.format("LoggerFactory is not a Logback LoggerContext but Logback is on "+ "the classpath. Either remove Logback or the competing "+ "implementation (%s loaded from %s). If you are using "+ "WebLogic you will need to add 'org.slf4j' to "+ "prefer-application-packages in WEB-INF/weblogic.xml",factory.getClass(), getLocation(factory)));return (LoggerContext) factory;
}
获取LoggerContext
并初始化,具体逻辑是在slf4j
,这里不展开。