SpringBoot事件监听器发布顺序
- ApplicationStartingEvent在运行开始时发送,但在进行任何处理之前(侦听器和初始化程序的注册除外)发送
- 在创建上下文之前,将发送ApplicationEnvironmentPreparedEvent
- 准备ApplicationContext并调用ApplicationContextInitializers之后,将发送ApplicationContextInitializedEvent
- 读取完配置类后发送ApplicationPreparedEvent
- 在刷新上下文之后但在调用任何应用程序和命令行运行程序之前,将发送ApplicationStartedEvent
- 紧随其后发送带有LivenessState.CORRECT的AvailabilityChangeEvent,以指示该应用程序被视为处于活动状态
- 在调用任何应用程序和命令行运行程序之后,将发送ApplicationReadyEvent
紧随其后发送ReadabilityState.ACCEPTING_TRAFFIC的AvailabilityChangeEvent,以指示应用程序已准备就绪,如果启动时发生异常,则发送ApplicationFailedEvent
启动SpringBoot应用的方式
调用SpringApplication.run启动springboot应用
SpringApplication.run(Application.class, args);
使用自定义SpringApplication进行启动
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
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创建环境变量对象
此时已经读取到了: 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)**