LoggingApplicationListener 的执行
LoggingApplicationListener 的主要作用是配置LoggingSystem, 如果 环境 包含 loggingconfig 属性,LoggingApplicationListener 将用于引导 日志记录系统,否则使用默认配置。
如果环境包含 logging.level.*和日志记录组,则可以使用 logging.group 定义日志记录级别。
关于 LoggingApplicationL istener 的重点功能我们后面章节再进行讲解。
LoggingApplicationListener 实现自 GenericApplicationListener 接口,具有监听器的特性。
因此,执行 EventPublishingRunListener 广播事件之后,LoggingApplicationListener 便会监听到对应的事件并执行 onApplicationEvent 方法中的逻辑判断,有针对性地处理不同的事件,相关代码如下。
@Overridepublic void onApplicationEvent(ApplicationEvent event) {if (event instanceof ApplicationStartingEvent) {// springboot 启动时触发onApplicationStartingEvent( (ApplicationStartingEvent) event);} else if (event instanceof ApplicationEnvironmentPreparedEvent) {// Environment 环境准备初级阶段触发onApplicationEnvironmentPreparedEvent( (Applicat ionEnvironmentPrepared-Event) event);} else if (event instanceof ApplicationPreparedEvent) {//应用上下文准备完成,但未刷新时触发onApplicationPreparedEvent( (Applicat ionPreparedEvent) event);else if (event instanceof ContextClosedEvent&& ((ContextClosedEvent) event). getApplicationContext() . getParent() == null) {//容器关闭时处理onContextClosedEvent( );} else if (event instanceof ApplicationFailedEvent) {//启动失败时处理onApplicationFailedEvent();}}
以上代码中的事件处理基本涵盖了 Spring Boot 启动的不同阶段和不同状况,比如 SpringBoot 刚刚启动阶段、环境准备初级阶段、应用上下文准备完成阶段、容器关闭阶段、应用程序启动失败等。后面章节我们会对这些过程中日志系统是如何处理的进行详解介绍。
![8ef9749f379b935e57073ff9630d3355.png](https://img-blog.csdnimg.cn/img_convert/8ef9749f379b935e57073ff9630d3355.png)
ApplicationStartingEvent 事件处理
在 Spring Boot 的启动过程中,通过 SpringApplicationRunListeners 类间接的调用了EventPublishingRunListener 中 的 各 类 事 件 的 发 布 方 法 , 最 终 被 LoggingApplicationListener 监听并进行处理。在后续的讲解中,我们省略这个中间调用过程,直接讲解 Logging-ApplicationL istener 接收到事件后的处理。
Spring Boot 刚 刚 启 动 时 发 布 了 ApplicationStartingEvent 事 件 , LoggingApplication-Listener 中的 onApplicationStartingEvent 方法便被调用了,该方法源码如下。
private void onApplicat ionStartingEvent(ApplicationStartingEvent event)this .loggingSystem = LoggingSystem. get(event . getSpringApplication(). getClassLoader()) ;this. loggingSystem. beforeInitialize();}
在 onApplicationStartingEvent 方法中,首先获得一个 LoggingSystem 对象,然后调用对象的 beforelnitialize 方 法进行预初始化操作。也就是说在 Spring Boot 开始启动时,日志系统做了两件事:创建 LoggingSystem 对象和预初始化操作。
LoggingSystem 为日志系统的通用抽象类,其中也提供了获取 LoggingSystem 对象的静态方法。上面 LoggingSystem 的创建便 是调用其 get 方法获得,相关代码如下。
public static LoggingSystem get(ClassLoader classLoader) {//从系统变量中获得 L oggingSystem 的类名String loggingSystem = System. getProperty(SYSTEM PROPERTY);f (StringUtils . hasLength(loggingSystem)) {if (NONE . equals(loggingSystem))return new NoOpLoggingSystem();/如果存在,则通过反射进行对象的初始化return get(classLoader, loggingSystem);// MSYSTEMS 筛选并初始化 LoggingSystem 对象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"));}
该方法首先判断系统中是否配置了 LoggingSystem 的配置,存在且不为“none”时,则利用反射机制进行初始化;如果明确配置为"none”,则返回 NoOpL oggingSystem 对象。实例化配置的 L oggingSystem 相关代码如下。
private static LoggingSystem get(ClassLoader classLoader, String loggingSystemClass) {tryClass> systemClass = ClassUtils . forName( loggingSystemClass, classLoader);Constructor> constructor = systemClass . getDeclaredConstructor(Class-Loader.class);constructor . setAccessible(true);return (LoggingSystem) constructor. newInstance(classLoader);} catch (Exception ex) {throw new IllegalStateException(ex);}}
以上代码就是通过获取指定类的构造器,调用其 newInstance 方法来创建 LoggingSystem对象的。
如果系统中不存在该对象的配置,则从 SYSTEMS 筛选获取第一个符合条件的值,然后进行初始化。SYSTEMS 为 L oggingSystem 的静态变量,通过静态代码块进行初始化,相关代码如下。
private static final Map SYSTEMS;static {Map systems = new Linked