在SpringBoot里面的spring.factories里面有注册一个org.springframework.boot.context.logging.LoggingApplicationListener,这个监听器起到了加载具体的logging的能力。
我们分别看下在sb启动的不同的阶段,此listener所做的事情,在开始启动的阶段,如下
private void onApplicationStartingEvent(ApplicationStartingEvent event) {
//根据classloader加载日志模块,哪个加载成功,就使用哪个
this.loggingSystem = LoggingSystem
.get(event.getSpringApplication().getClassLoader());
//执行具体的logging组件的回调方法-beforeInitialize
this.loggingSystem.beforeInitialize();
}
而对于LoggingSystem.get(event.getSpringApplication().getClassLoader())方法,
/**
* Detect and return the logging system in use. Supports Logback and Java Logging.
* @param classLoader the classloader
* @return the logging system
*/
public static LoggingSystem get(ClassLoader classLoader) {
//是否有自己配置日志模块
String loggingSystem = System.getProperty(SYSTEM_PROPERTY);
if (StringUtils.hasLength(loggingSystem)) {
if (NONE.equals(loggingSystem)) {
return new NoOpLoggingSystem();
}
//如果有配置,根据配置的loggingSystemClass反射去初始化
return get(classLoader, loggingSystem);
}
//如果没有,那么系统默认按照,logback,log4j,jul的顺序去加载对应的class,哪个加载成功就使用哪个日志模块,我本地使用了logback,故而加载出来loggingSystem就是logback。(slf4j+logback)是spring推荐的标准的logging配置。
return SYSTEMS.entrySet().stream()
.filter((entry) -> ClassUtils.isPresent(entry.getKey(), classLoader))
.map((entry) -> get(classLoader, entry.getValue())).findFirst()
.orElseThrow(() -> new IllegalStateException(
"No suitable logging system located"));
}
private static LoggingSystem get(ClassLoader classLoader, String loggingSystemClass) {
try {
Class<?> systemClass = ClassUtils.forName(loggingSystemClass, classLoader);
return (LoggingSystem) systemClass.getConstructor(ClassLoader.class)
.newInstance(classLoader);
}
catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
在上一步主要是确定使用的logging组件(一下默认使用的组件是logback),确定了组件之后,接下来就是对选择的组件进行初始化的操作。那在什么时候进行初始话的操作呢,肯定是在所有的系统变量加载完成之后,根据配置的系统变量来对组件进行初始化了。所以初始化发生在如下
private void onApplicationEnvironmentPreparedEvent(
ApplicationEnvironmentPreparedEvent event) {
if (this.loggingSystem == null) {
this.loggingSystem = LoggingSystem
.get(event.getSpringApplication().getClassLoader());
}
initialize(event.getEnvironment(), event.getSpringApplication().getClassLoader());
}
protected void initialize(ConfigurableEnvironment environment,
ClassLoader classLoader) {
new LoggingSystemProperties(environment).apply();
LogFile logFile = LogFile.get(environment);
if (logFile != null) {
logFile.applyToSystemProperties();
}
//初始化sb的logging级别
initializeEarlyLoggingLevel(environment);
//根据环境变量初始化系统
initializeSystem(environment, this.loggingSystem, logFile);
//确定最终的logging等级
initializeFinalLoggingLevels(environment, this.loggingSystem);
//注册shutdown的钩子方法
registerShutdownHookIfNecessary(environment, this.loggingSystem);
}
第三步,将应用启动起来之后,将loggingSystem作为bean注册到了容器,后期我们会根据这个bean做动态化的扩展和增强(重点打钩)
private void onApplicationPreparedEvent(ApplicationPreparedEvent event) {
ConfigurableListableBeanFactory beanFactory = event.getApplicationContext()
.getBeanFactory();
if (!beanFactory.containsBean(LOGGING_SYSTEM_BEAN_NAME)) {
beanFactory.registerSingleton(LOGGING_SYSTEM_BEAN_NAME, this.loggingSystem);
}
}
而onContextClosedEvent() 和onApplicationFailedEvent可以忽略,主要是应用启动失败的话,调用this.loggingSystem.cleanUp()。做一些清理工作。
网友评论