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

    科技2022-08-09  106

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

    前言版本ApplicationContextInitializedEventApplicationContextInitializedEvent 对应的监听器 ApplicationPreparedEventApplicationPreparedEvent 对应的监听器 ApplicationStartedEventApplicationStartedEvent 对应的监听器 ApplicationReadyEventApplicationReadyEvent 对应的监听器 ApplicationFailedEvent总结参考

    前言

    上一章节介绍了 ApplicationStartingEvent ApplicationEnvironmentPreparedEvent 的 生命周期 动作,以及对应 监听器 的行为,本章节继续介绍剩余 事件 相关

    版本

    SpringBoot 2.3.3.RELEASE

    ApplicationContextInitializedEvent

    /** * 做一些 容器 的初步配置,比如 * 设置environment、容器后处理、执行ApplicationContextInitializer#initialize * 此处发布 ApplicationContextInitializedEvent * 还有注册若干单例、SpringApplication 属性设置、后处理器注册、主类加载 * 此处发布 ApplicationPreparedEvent */ prepareContext(context, environment, listeners, applicationArguments, printedBanner); ----------------- prepareContext ----------------- private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { // 把 environment 交给 容器 context.setEnvironment(environment); /** * 容器后处理 * 1)注册 BeanNameGenerator 单例(如果存在) * 2)设置 resourceLoader * 3)设置 容器 的 conversionService(ApplicationConversionService) */ postProcessApplicationContext(context); // 执行所有 ApplicationContextInitializer#initialize applyInitializers(context); // 发布 ApplicationContextInitializedEvent listeners.contextPrepared(context); // ... } ------------ EventPublishingRunListener ------------ public void contextPrepared(ConfigurableApplicationContext context) { this.initialMulticaster .multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context)); } 设置 environment 属性容器 的后处理,包括注册 BeanNameGenerator 单例,设置 resourceLoader 属性、设置 conversionService 属性依次执行所有 ApplicationContextInitializer#initialize 方法,ApplicationContextInitializer 即构造方法中 自动装配 的 initializers 属性,共有 7 个 1)DelegatingApplicationContextInitializer:收集所有 environment 中 context.initializer.classes 属性配置的自定义 ApplicationContextInitializer,并执行 initialize 方法,换句话说自定义的 ApplicationContextInitializer 优先级最高 2)SharedMetadataReaderFactoryContextInitializer:注册 CachingMetadataReaderFactoryPostProcessor 后处理器 3)ContextIdApplicationContextInitializer:生成一个 ContextId 类型的 容器标识,并将其注册为 单例 4)ConfigurationWarningsApplicationContextInitializer:注册一个 ConfigurationWarningsPostProcessor 后处理器 5)RSocketPortInfoApplicationContextInitializer:设置 local.rsocket.server.port 属性 6)ServerPortInfoApplicationContextInitializer:设置 local.server.port 等属性 7)ConditionEvaluationReportLoggingListener:设置 ConditionEvaluationReport 属性并注册为 单例发布 ApplicationContextInitializedEvent

    ApplicationContextInitializedEvent 对应的监听器

    BackgroundPreinitializer:针对 ApplicationContextInitializedEvent 无动作DelegatingApplicationListener:同时发布该事件给所有 自定义监听器

    ApplicationPreparedEvent

    /** * 做一些 容器 的初步配置,比如 * 设置environment、容器后处理、执行ApplicationContextInitializer#initialize * 此处发布 ApplicationContextInitializedEvent * 还有注册若干单例、SpringApplication 属性设置、后处理器注册、主类加载 * 此处发布 ApplicationPreparedEvent */ prepareContext(context, environment, listeners, applicationArguments, printedBanner); ----------------- prepareContext ----------------- private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { // ... ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); /** * 注册单例 * springApplicationArguments -> applicationArguments * springBootBanner -> printedBanner */ beanFactory.registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) { beanFactory.registerSingleton("springBootBanner", printedBanner); } /** * 是否允许 循环依赖 * 该属性在这之前可由 spring.main 属性设置 */ if (beanFactory instanceof DefaultListableBeanFactory) { ((DefaultListableBeanFactory) beanFactory) .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } // 注册 后置处理器 LazyInitializationBeanFactoryPostProcessor if (this.lazyInitialization) { context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()); } Set<Object> sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); // 创建对应的 BeanDefinitionLoader 加载所有资源类 // 注册对应的 BeanDefinition // 默认情况下,会用 BeanDefinitionLoader 的 成员属性 // AnnotatedBeanDefinitionReader 来解析 load(context, sources.toArray(new Object[0])); // 发布 ApplicationPreparedEvent listeners.contextLoaded(context); } ------------ EventPublishingRunListener ------------ public void contextLoaded(ConfigurableApplicationContext context) { for (ApplicationListener<?> listener : this.application.getListeners()) { if (listener instanceof ApplicationContextAware) { ((ApplicationContextAware) listener).setApplicationContext(context); } context.addApplicationListener(listener); } this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context)); } 注册 ApplicationArguments、Banner 对应的 单例设置 allowBeanDefinitionOverriding 属性,由 spring.main 属性控制注册一个 LazyInitializationBeanFactoryPostProcessor 后处理器加载 资源类,这个步骤可以对应成容器的 register 方法,默认情况下由 BeanDefinitionLoader 的成员属性 AnnotatedBeanDefinitionReader annotatedReader 加载主类,主类子路径下的其他配置类则在 ComponentScanAnnotationParser 解析主类时由 ClassPathBeanDefinitionScanner 注册发布 ApplicationPreparedEvent把 SpringApplication 的 监听器 与 容器 绑定起来,同时将 SpringApplication 的 监听器 注册到 容器 中,也就是说 SpringApplication 可以监听到 容器 的相关事件

    ApplicationPreparedEvent 对应的监听器

    CloudFoundryVcapEnvironmentPostProcessor:略ConfigFileApplicationListener:注册一个 PropertySourceOrderingPostProcessor 后处理器LoggingApplicationListener:注册几个日志相关的 单例BackgroundPreinitializer:针对 ApplicationPreparedEvent 无动作DelegatingApplicationListener:同时发布该事件给所有 自定义监听器

    ApplicationStartedEvent

    // 调用容器的 refresh 方法 refreshContext(context); // 空实现,供拓展 afterRefresh(context, applicationArguments); stopWatch.stop(); // 打印日志 if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } /** * 此处发布 ApplicationStartedEvent */ listeners.started(context); ------------ EventPublishingRunListener ------------ public void started(ConfigurableApplicationContext context) { context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context)); AvailabilityChangeEvent.publish(context, LivenessState.CORRECT); } 在发布 ApplicationStartedEvent 前,有一个很重要的动作 refreshContext,此处调用了 容器 的 refresh 方法,这是 容器 最核心的方法,配置(刷新) 整个 Spring 容器,单例bean 的注册就是发生在此处 关于 容器 的 refresh 方法,可以阅读下面文章

    【源码】Spring —— BeanFactory 解读 7 AbstractApplicationContext

    发布 ApplicationStartedEvent 后还发布了一个 AvailabilityChangeEvent 事件

    ApplicationStartedEvent 对应的监听器

    BackgroundPreinitializer:针对 ApplicationStartedEvent 无动作DelegatingApplicationListener:同时发布该事件给所有 自定义监听器

    ApplicationReadyEvent

    /** * 此处发布 ApplicationReadyEvent */ listeners.running(context); ------------ EventPublishingRunListener ------------ public void running(ConfigurableApplicationContext context) { context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context)); AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC); }

    发布 ApplicationReadyEvent 后还发布了一个 AvailabilityChangeEvent 事件

    ApplicationReadyEvent 对应的监听器

    BackgroundPreinitializer:在发布 ApplicationEnvironmentPreparedEvent 事件时,此监听器在后台启动一个线程执行 预热 操作,其用到一个 CountDownLatch 使得在 预热 操作执行完成前,所有线程会阻塞在此处。则 ApplicationReadyEvent 事件到达时,如果 预热 完成,预热线程中断 关于 CountDownLatch,可以阅读下面文章

    【源码】JUC —— CountDownLatch 浅析

    DelegatingApplicationListener:同时发布该事件给所有 自定义监听器

    ApplicationFailedEvent

    容器 启动失败,则发布 ApplicationFailedEvent

    总结

    本文屏蔽了大量细节,浅析了 SpringBoot 在 生命周期 发布的所有 事件 及对应的 事件监听器,Spring 基于 后置处理器(BeanPostProcessor) 进行拓展,而 SpringBoot 则引申出 SpringApplication 的抽象概念,基于 事件机制 进行拓展,对于其内部 容器(ApplicationContext) 的则可以通过 监听器 注册 BeanPostProcessor 的方式继续拓展

    参考

    不懂SpringApplication生命周期事件?那就等于不会Spring Boot嘛

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

    Processed: 0.012, SQL: 8