在这个启动过程中会有各种SpringBoot对外提供的扩展接口来对不同启动阶段进行自定义操作。
了解启动过程也是为了让我们更好理解SpringBoot提供的扩展接口使用
tomcat会查询context上下文中实现ServletContainerInitializer接口的类,然后调用类的onStartup(Set<Class<?>> c, ServletContext ctx)方法
Spring的SpringServletContainerInitializer实现了这个ServletContainerInitializer接口,
会获取WebApplicationInitializer接口的实现类,调用onStartup()方法
SpringBoot的类SpringBootServletInitializer实现了Spring的WebApplicationInitializer扩展接口,
会在onStartup()方法中创建SpringApplication类,并调用SpringApplication.run()来完成启动项目
与我们在开发时调用Application.main()方法启动时一样的原理
@SpringBootApplication public class Application extends SpringBootServletInitializer { public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { this.setRegisterErrorPageFilter(false); // 错误页面有容器来处理,而不是SpringBoot return builder.sources(Application.class); } }
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances( SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); prepareContext(context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } listeners.started(context); callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; }
2 、触发ApplicationStartingEvent事件
SpringBoot对Spring的ApplicationListener进行了一个包装
在启动过程中使用SpringApplicationRunListener接口的实现类EventPublishingRunListener来触发各种事件
public interface SpringApplicationRunListener { starting ==> ApplicationStartingEvent environmentPrepared ==> ApplicationEnvironmentPreparedEvent contextPrepared ==> 无 contextLoaded ==》 ApplicationPreparedEvent started ==》 ApplicationStartedEvent running ==》 ApplicationReadyEvent failed ==》 ApplicationFailedEvent }
我们可以通过自定义SpringApplicationRunListener来在不同阶段操作,也可以通过配置ApplicationListener来完成不同阶段的操作。
这个开始启动事件触发操作:主要是进行日志系统初始化,字符集设置等操作
最开始触发的监听器:LoggingApplicationListener和BackgroundPreinitializer
LoggingApplicationListener日志系统实例生成,执行初始化前方法loggingSystem.beforeInitialize() BackgroundPreinitializer 后台线程预初始化任务,用于耗时任务的初始化 1.默认类型转换器,format格式解析初始化 2.初始化校验器 3. 默认处理表单数据的消息转换器初始化的AllEncompassingFormHttpMessageConverter 4.初始化tomcat的MBeanFactory 5. 字符集初始化
3、获取命令行参数和准备上下文环境
prepareEnvironment(listeners, applicationArguments)
主要是ConfigFileApplicationListener监听这个事件
会调用EnvironmentPostProcessor 环境后置处理器接口
还有这个类本身后置处理器会将配置文件加载到environment环境的属性源列表中
环境准备事件触发操作:配置文件属性源加载,日志系统配置环境属性设置
EnvironmentPostProcessor 这个接口扩展处理上下文环境操作
DelegatingApplicationListener,这个委托代理监听器只能代理ApplicationEnvironmentPreparedEvent环境准备完成事件
4、初始化上下文信息
为context上下文设置reader和scanner,用于获取bean定义 调用ApplicationContextInitializer接口,对上下文进行初始化 将ApplicationArguments和SpringApplication作为bean注册到BeanFactory中 load(context, sources.toArray(new Object[0])); 这里是将应用启动类,即Application.java类,将其生成BeanDefinition即bean定义,绑定到beanFactory中 触发ApplicationPreparedEvent事件
ApplicationContextInitializer接口, 对上下文进行初始化操作
触发ApplicationPreparedEvent事件
网上资料:ApplicationPreparedEvent事件:在Bean定义加载之后、bean初始化之前,刷新上下文之前触发
自己调试:这个bean定义加载只是对Application.java启动类和内置的bean定义进行加载,我们项目中自定义的bean定义还是没有进行加载。
将ConfigFileApplicationListener # PropertySourceOrderingPostProcessor添加到ApplicationContext的BeanFactoryPostProcessors列表中,这个是BeanFactory的后置处理器
将Bean名称为:“springBootLoggingSystem”日志系统注册到beanfactory中
配置beanfactory
设置bean类加载器,设置SpEL表达式解析器,注册配置属性编辑器,
初始化BeanPostProcessor(如ApplicationContextAwareProcessor),
设置忽略自动装配的接口,
注册默认环境bean(environment,systemProperties,systemEnvironment)
设置忽略自动装配的接口是Spring默认指定的Aware及其子接口
当类A中有属性是类B时,在初始化A的bean时,
如果类B是实现了Aware或其子接口时。不会为A自动注入类B
而是要通过B实现了Aware其子接口的接口方法来为A设置属性
一般来说:实现了Aware其子接口的实现类都是作为工具类,或者配置类
BeanPostProcessor接口:对bean初始化前后做一些操作逻辑,比如设置bean的属性,或对特殊的bean的方法进行调用等
5.3 postProcessBeanFactory(beanFactory)
context的子类在配置好BeanFactory后的扩展方法,
这里是AnnotationConfigServletWebServerApplicationContext类 添加了一个后置处理器,一个忽略自动注入接口
beanFactory.addBeanPostProcessor(WebApplicationContextServletContextAwareProcessor) beanFactory.ignoreDependencyInterface(ServletContextAware.class)
5.4 invokeBeanFactoryPostProcessors(beanFactory)
会将ApplicationContext中设置的beanFactoryPostProcessors列表
转换成BeanDefinitionRegistryPostProcessor(registryProcessors 注册处理器)
和BeanFactoryPostProcessor(regularPostProcessors 规则处理器)
内置beanFactory后置处理器列表
SharedMetadataReaderFactoryContextInitializer # CachingMetadataReaderFactoryPostProcessor
ConfigurationWarningsApplicationContextInitializer # ConfigurationWarningsPostProcessor
ConfigFileApplicationListener # PropertySourceOrderingPostProcessor
会先调用内置的注册处理器的postProcessBeanDefinitionRegistry(registry);方法
进行自定义bean的注册,或者对beanFactory中的bean定义的属性值进行修改
比如
SharedMetadataReaderFactoryContextInitializer # CachingMetadataReaderFactoryPostProcessor
会将SharedMetadataReaderFactoryContextInitializer.SharedMetadataReaderFactoryBean类创建bean定义注册到BeanFactory中,
还有修改ConfigurationAnnotationProcessor类的metadataReaderFactory属性值为SharedMetadataReaderFactoryBean
也就是说只要有@Configuration、@Component、@ComponentScan、@Import、@ImportResource和@Bean中的其中一个注解,就会将bean注册到beanfactory中
@Import注解处理,如果导入的是ImportSelector接口实现类,会调用接口方法String[] selectImports()
通过返回字符串数组。里面是配置类名称。动态选择要导入的配置类全名
除了解析上面注解定义的bean外
还会处理@PropertySource注解,将指定的配置属性源设置到environment环境中
this.reader.loadBeanDefinitions(configClasses);这里会进行额外的bean定义加载:(被Import导入的类加载,方法定义的bean加载,资源文件中定义的bean)
后置处理器处理过程中会被调用三次
1. 第一次是执行ConfigurationClassPostProcessor后置处理器,获取项目中的bean定义
执行过了后置处理器不会再次执行
2. 第二次是在所有bean定义中获取有加@Order注解的BeanDefinitionRegistryPostProcessor实现类,执行后置处理器。 3. 第三次是再次获取没有执行过的处理器进行再次执行 比如mybatis的MapperScannerConfigurer就是在这里执行实现mybatis注解的bean定义加载 4. 最后是执行registryProcessors注册器和regularPostProcessors规则处理器的postProcessBeanFactory(beanFactory)方法
PriorityOrdered接口
PropertySourcesPlaceholderConfigurer
Ordered接口
没有实现上面接口的
org.springframework.boot.context.properties.ConfigurationBeanFactoryMetadata
preserveErrorControllerTargetClassPostProcessor
dataSourceInitializerSchedulerDependencyPostProcessor
5.5、registerBeanPostProcessors(beanFactory);
beanFactory.addBeanPostProcessor(postProcessor)
5.6、initMessageSource():一般是我们用来初始化我们国际化文件的
5.8、onRefresh():初始化其他的子容器类中的bean,同时创建spring的内置tomcat,
5.9、registerListeners():
添加用户设置applicationListeners,然后从beanFactory获取ApplicationListener, 然后发布需要earlyApplicationEvents事件 是从beanFactory中获取所有实现ApplicationListener接口的类, getBeanNamesForType(ApplicationListener.class, true, false) 第一个type参数表示类型,第二个参数是否包含非单例的bean 第三个参数是否允许提前初始化, true表示允许。会导致bean提前初始化, false,表示不允许提前初始化,如果实在spring启动过程中,这个参数需要设置为false
6.0、finishBeanFactoryInitialization(beanFactory);
缓存所有bean定义元数据 bean definition metadata
beanFactory.preInstantiateSingletons();
实例化所有剩余的(非延迟初始化)单例。
在这个过程中会调用beanPostProcessors,bean实例化前后的处理器
在这个方法里会处理实现Aware接口的Bean类
invokeAwareMethods(beanName, bean);方法会处理实现了BeanNameAware,BeanClassLoaderAware,BeanFactoryAware接口实现了类的接口方法
接着调用applyBeanPostProcessorsBeforeInitialization 处理BeanPostProcessor bean调用初始化之前的处理
接着调用bean的初始化方法invokeInitMethods(beanName, wrappedBean, mbd);
接着调用bean的初始化方法之后的后置处理器
ApplicationContextAwareProcessor:
处理实现EnvironmentAware,EmbeddedValueResolverAware,ResourceLoaderAware,ApplicationEventPublisherAware,MessageSourceAware,ApplicationContextAware这些接口的实现bean类在
在初始化回调之前调用对应接口方法做对应的操作。
比如initializingBean的afterPropertiesSet()方法之前或@Bean注解设置的init-method之前调用
WebApplicationContextServletContextAwareProcessor
处理实现了ServletContextAware接口的bean,可以通过setServletContext(ServletContext)方法获取servletContext
完成上下文刷新,
清除上下文级别的resources缓存(MetadataReader封装的资源,比如扫描的配置类)
初始化lifecycleProcessor,用来管理spring生命周期的onRefresh作用是容器启动成功,onClose是只应用要关闭的时候
然后触发ContextRefreshedEvent事件
refreshContext(context);执行完成
7、afterRefresh(context, applicationArguments);
这里没有操作
8、触发ApplicationStartedEvent事件
9、callRunners(context, applicationArguments)
从beanfactory中获取ApplicationRunner和CommandLineRunner接口实现类
调用他们的run方法
10、触发ApplicationReadyEvent事件