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());
@Override
public 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());
@Override
public 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());
@Override
public 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
,这里不展开。