【源码】SpringBoot 生命周期及相关事件浅析 一

    科技2022-07-12  115

    【源码】SpringBoot 生命周期及相关事件浅析 一

    前言版本SpringApplicationSpringApplication 启动SpringApplication 实例构造SpringApplication.run ApplicationStartingEventApplicationStartingEvent 对应的监听器 ApplicationEnvironmentPreparedEventApplicationEnvironmentPreparedEvent 对应的监听器 总结

    前言

    阅读本系列章节前,建议复习一下 Spring事件、事件监听器、事件发布 相关

    【源码】Spring —— ApplicationEvent ApplicationListener ApplicationEventMulticaster

    SpringBoot 提供了事件父类 SpringApplicationEvent,继承自 ApplicationEvent

    其下定义了 7 个事件,本系列结合部分源码解读 SpringBoot 何时发布这些 事件?对应的 事件监听器 都做了什么?

    版本

    SpringBoot 2.3.3.RELEASE

    SpringApplication

    SpringApplication,Spring 应用的抽象。在 SpringBoot 中,我们可以通过一个简单的 main 方法,来启动一个 Spring 应用

    SpringApplication 启动

    public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) { return run(new Class[]{primarySource}, args); } public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { return (new SpringApplication(primarySources)).run(args); }

    即创建一个 SpringApplication 实例,调用 run 方法

    SpringApplication 实例构造

    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); this.webApplicationType = WebApplicationType.deduceFromClasspath(); setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }

    属性的初始化,其中 initializers 和 listeners 从 spring.factories 文件读取加载

    SpringApplication.run

    public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); // 开始计时 stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); /** * 加载对应的 SpringApplicationRunListener * 封装成 SpringApplicationRunListeners */ SpringApplicationRunListeners listeners = getRunListeners(args); /** * SpringApplicationRunListener#starting, * 此处发布 ApplicationStartingEvent */ listeners.starting(); try { // 解析运行参数为 ApplicationArguments ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); /** * 创建并配置 Environment * 此处发布 ApplicationEnvironmentPreparedEvent */ ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); // 设置 spring.beaninfo.ignore 属性 configureIgnoreBeanInfo(environment); // Banner 打印 Banner printedBanner = printBanner(environment); // 创建对应的 容器对象(ConfigurableApplicationContext) context = createApplicationContext(); // 装配对应的 SpringBootExceptionReporter exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); /** * 做一些 容器 的初步配置,比如 * 设置environment、容器后处理、执行ApplicationContextInitializer#initialize * 此处发布 ApplicationContextInitializedEvent * 还有注册若干单例、SpringApplication 属性设置、后处理器注册、主类加载 * 此处发布 ApplicationPreparedEvent */ prepareContext(context, environment, listeners, applicationArguments, printedBanner); // 调用容器的 refresh 方法 refreshContext(context); // 空实现,供拓展 afterRefresh(context, applicationArguments); stopWatch.stop(); // 打印日志 if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } /** * 此处发布 ApplicationStartedEvent */ listeners.started(context); // 调用所有 ApplicationRunner CommandLineRunner 类型 bean 的 run 方法 callRunners(context, applicationArguments); } catch (Throwable ex) { /** * 容器启动失败处理 * 此处发布 ApplicationFailedEvent */ handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { /** * 此处发布 ApplicationReadyEvent */ listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; }

    此处先贴出 run 方法的所有代码,可以看到 SpringApplication 在完成对应的动作后就会发布对应的 事件,触发对应的 监听器,监听器 可能输出对应的日志,也可能类似于 Spring 的 后置处理器,对 容器 environment 等进行配置、处理,也可能 无动作

    接下来我们依次解读发布的 事件,以及对应的 监听器

    ApplicationStartingEvent

    /** * 加载对应的 SpringApplicationRunListener * 封装成 SpringApplicationRunListeners */ SpringApplicationRunListeners listeners = getRunListeners(args); /** * SpringApplicationRunListener#starting, * 此处发布 ApplicationStartingEvent */ listeners.starting(); ------------ EventPublishingRunListener ------------ public void starting() { this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args)); } 这里实例化了 SpringApplicationRunListeners,SpringApplicationRunListeners 就是对内部 SpringApplicationRunListener 的一层封装,之后 SpringApplication 生命周期相关的 事件 将由 SpringApplicationRunListeners 来发布,其本质就是循环调用内部所有 SpringApplicationRunListener 对应方法SpringApplicationRunListener 就是一个模板接口,定义了 SpringApplication 生命周期要发布 事件 的模板,SpringBoot 提供了一个实现类 EventPublishingRunListener,在上述代码的 getRunListeners 方法中,自动装配并创建 EventPublishingRunListener 的示例返回EventPublishingRunListener 发布 事件 是委托给内部的 SimpleApplicationEventMulticaster 来实现的,即就是将 事件 发布给对应 事件监听器这里发布了 ApplicationStartingEvent 事件

    ApplicationStartingEvent 对应的监听器

    监听 ApplicationStartingEvent 的监听器有

    LoggingApplicationListener:日志相关BackgroundPreinitializer:针对 ApplicationStartingEvent 无动作DelegatingApplicationListener:针对 ApplicationStartingEvent 无动作LiquibaseServiceLocatorApplicationListener:liquibase 相关

    ApplicationEnvironmentPreparedEvent

    /** * 创建并配置 Environment * 此处发布 ApplicationEnvironmentPreparedEvent */ ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); ---------------- prepareEnvironment ---------------- private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { // 创建对应的 ConfigurableEnvironment 对象 ConfigurableEnvironment environment = getOrCreateEnvironment(); /** * 初步配置 environment 比如 启动参数 等 */ configureEnvironment(environment, applicationArguments.getSourceArgs()); /** * 给 environment 添加一个名为 * configurationProperties 的 PropertySource */ ConfigurationPropertySources.attach(environment); /** * 发布 ApplicationEnvironmentPreparedEvent 事件 */ listeners.environmentPrepared(environment); /** * 把 spring.main 属性绑定到当前 * SpringApplication 实例 */ bindToSpringApplication(environment); if (!this.isCustomEnvironment) { environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass()); } ConfigurationPropertySources.attach(environment); return environment; } ------------ EventPublishingRunListener ------------ public void environmentPrepared(ConfigurableEnvironment environment) { this.initialMulticaster .multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment)); } 首先创建了 ConfigurableEnvironment 实例初步配置后,发布 ApplicationEnvironmentPreparedEvent 事件,该 事件 相关的 监听器 动作比较大,SringBoot 强大的配置能力也基于此实现后续动作,比如绑定相关配置到当前 SpringApplication 实例,之后返回配置好的 ConfigurableEnvironment 实例 继续阅读之前,建议了解以下 Spring Environment

    【源码】Spring —— Environment 解读

    ApplicationEnvironmentPreparedEvent 对应的监听器

    ConfigFileApplicationListener:在这个 监听器 中,自动装配其他 4 个 EnvironmentPostProcessor(ConfigFileApplicationListener 本身也是一个 EnvironmentPostProcessor),然后依次调用了它们的 postProcessEnvironment 方法 1)SystemEnvironmentPropertySourceEnvironmentPostProcessor:将 environment 中名为 systemEnvironment 的 PropertySource 替换为 OriginAwareSystemEnvironmentPropertySource 类型的(可调用 getOrigin 方法获取对应的 SystemEnvironmentOrigin) 2)SpringApplicationJsonEnvironmentPostProcessor:解析 environment 所有 PropertySource 中的 spring.application.json 和 SPRING_APPLICATION_JSON 属性 3)CloudFoundryVcapEnvironmentPostProcessor:SpringCloud 相关 4)ConfigFileApplicationListener:该监听器本身也是最核心的 EnvironmentPostProcessor:给 environment 添加一个名为 random 的 PropertySource;加载 environment 的 activeProfiles 属性;加载配置文件的所有配置到 environment 的 propertySources 中 5)DebugAgentEnvironmentPostProcessor:Spring Reactor 相关AnsiOutputApplicationListener:解析 spring.output.ansi.enabled 属性LoggingApplicationListener:日志相关ClasspathLoggingApplicationListener:日志输出 classpath 信息BackgroundPreinitializer:启动一个线程异步执行 实例化DefaultFormattingConversionService、实例化AllEncompassingFormHttpMessageConverter 等动作,该行为可以通过 spring.backgroundpreinitializer.ignore 属性控制DelegatingApplicationListener:解析 context.listener.classes 属性对应的所有自定义的 事件监听器,在这之后的事件也会同样发布给这些 监听器。换句话说,用户可以 自定义监听器 监听 ApplicationEnvironmentPreparedEvent 及其之后的所有 ApplicationEvent 事件(注意,监听不到 ApplicationStartingEvent)FileEncodingApplicationListener:如果设置了 spring.mandatory-file-encoding 属性,则当其与系统的 file.encoding 属性不同时,输出相关日志信息

    总结

    本章节介绍了 ApplicationStartingEvent ApplicationEnvironmentPreparedEvent 的 生命周期 动作,以及对应 监听器 的行为,避免篇幅太长,下章节继续

    下一篇:【源码】SpringBoot 生命周期及相关事件浅析 二

    Processed: 0.011, SQL: 8