SpringBoot事件监听器发布顺序

  • ApplicationStartingEvent在运行开始时发送,但在进行任何处理之前(侦听器和初始化程序的注册除外)发送
  • 在创建上下文之前,将发送ApplicationEnvironmentPreparedEvent
  • 准备ApplicationContext并调用ApplicationContextInitializers之后,将发送ApplicationContextInitializedEvent
  • 读取完配置类后发送ApplicationPreparedEvent
  • 在刷新上下文之后但在调用任何应用程序和命令行运行程序之前,将发送ApplicationStartedEvent
  • 紧随其后发送带有LivenessState.CORRECT的AvailabilityChangeEvent,以指示该应用程序被视为处于活动状态
  • 在调用任何应用程序和命令行运行程序之后,将发送ApplicationReadyEvent
  • 紧随其后发送ReadabilityState.ACCEPTING_TRAFFIC的AvailabilityChangeEvent,以指示应用程序已准备就绪,如果启动时发生异常,则发送ApplicationFailedEvent

    启动SpringBoot应用的方式

    调用SpringApplication.run启动springboot应用

    1. SpringApplication.run(Application.class, args);

    使用自定义SpringApplication进行启动

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

    SpringBoot启动流程

  • 初始化SpringApplication: new SpringApplication(primarySources)

    • 将启动类放入primarySources

this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));

  • 推算当前web应用类型 webApplicationType

this.webApplicationType = WebApplicationType.deduceFromClasspath();

  • 读取ApplicationContextInitializer 初始化器

去spring.factories 中去获取所有key:org.springframework.context.ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));

  • 读取ApplicationListener 监听器

去spring.factories 中去获取所有key: org.springframework.context.ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

  • 将main方法所在的类放入mainApplicationClass

根据main方法推算出mainApplicationClass
this.mainApplicationClass = deduceMainApplicationClass();

  • 启动SpringBoot: SpringApplication.run
    • 记录启动开始时间

stopWatch.start();

  • 开启handless: configureHeadlessProperty()

设置java.awt.headless=true

  • 读取SpringApplicationRunListeners监听器运行器

ApplicationStartingEvent在运行开始时发送,但在进行任何处理之前
listeners.starting();

  • 发布1.ApplicationStartingEvent事件
    • doWithListeners: 每个事件都会记录以一个Step用于跟踪
    • StartupStep.tag(…)
  • 封装命令行参数ApplicationArguments

ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

  • 读取环境配置信息: prepareEnvironment

    • 根据webApplicationType创建环境变量对象

      1. 此时已经读取到了: java环境变量和系统环境变量
    • 配置环境变量

      • 读取SpringApplication.defaultProperties 和命令行参数configurePropertySources(environment, args);
      • 根据环境变量中spring.profiles.active 和 SpringApplication.additionalProfiles 激活当前profile

configureProfiles(environment, args);

     - **将现有环境信息设置为@ConfigurationProperties的数据源,并且放在第一位**
     - **发布2.ApplicationEnvironmentPrepareEvent**

ConfigFileApplicationListener会读取所有默认配置文件信息

     - **将spring.main的配置绑定到SpringApplication属性上**bindToSpringApplication(environment);
     - **将现有环境信息设置为@ConfigurationProperties的数据源,更新放在第一位**ConfigurationPropertySources.attach(environment);
  - **设置忽略bean:spring.beaninfo.ignroe**

configureIgnoreBeanInfo(environment);

  - **打印Banner**

Banner printedBanner = printBanner(environment);

  - **实例化Spring上下文AnnotationConfigServletWebServerApplicationContext**

context = createApplicationContext();

  - **初始化失败分析器**

exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);

  - **准备上下文: prepareContext**
     - **将当前环境信息设置到context**

context.setEnvironment(environment);

     - **调用ApplicationContextInitializer**

applyInitializers(context)

     - **发布3.ApplicatipnContextInitializedEvent**
     - **打印启动信息和profile.active信息**
if (this.logStartupInfo) {
      logStartupInfo(context.getParent() == null);
      logStartupProfileInfo(context);
   }

打印

: Starting ConfigurationFileApplication on DESKTOP-FGTQI9C with PID 18136 (D:\ideaworkspace\java\springboot\springboot_parent\02_configuration_file\target\classes started by zengjin in D:\ideaworkspace\java\springboot\springboot_parent)
: The following profiles are active: dev
     - **将applicationArguments、printedBanner注册到bean**
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
  beanFactory.registerSingleton("springBootBanner", printedBanner);
}
     - **设置不允许同名bean**

在spring中是允许的

if (beanFactory instanceof DefaultListableBeanFactory) {
    ((DefaultListableBeanFactory) beanFactory)
    .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
        - **关闭循环依赖**
     - **设置是否懒加载bean**
if (this.lazyInitialization) {
    context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
  }
     - **读取启动类为BeanDefinition**
        - 这是容器加载非常关键的一步, 因为要根据启动类加载所有bean , 在这里启动类就相当于配置文件xml ,, 如果你之前看过AnnotationConfigApplicationContext, 它也会读取配置类一个意思
     - **将SpringBoot的监听器添加到context,发布4.ApplicationPrepareEvent**
  - **刷新容器,加载IOC容器: refreshContext**
     - **AnnotationConfigServletWebServerApplicationContext#refresh**
        - **prepareRefresh()**
        - **ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory()**
        - **prepareBeanFactory(beanFactory);**
        - **postProcessBeanFactory(beanFactory);**
           - 注册BeanPostProceessor: WebApplicationContextServletContextAwareProcessor
              - ServletContextAware
              - ServletConfigAware
           - 忽略自动装配的接口方法: beanFactory.ignoreDependencyInterface(ServletContextAware.class)
           - 注册WebApplicationContext作用域
        - **invokeBeanFactoryPostProcessors(beanFactory)**