SpringBoot启动分析
1)IOC之容器启动阶段
这个阶段主要会进行:加载配置文件并解析,然后将解析后的数据封装为BeanDefinition实例,最后把这些保存了bean定义的BeanDefinition,注册到相应的BeanDefinitionRegistry,这样容器的启动工作就完成了。
配置文件:类似的有xml配置文件还有自动配置类
2)IOC之容器实例化阶段
当某个请求通过BeanFactory的getBean方法请求某个对象,或者因为依赖关系容器需要隐式的调用getBean时,就会触发第二阶段的活动:容器会首先检查所请求的对象之前是否已经实例化完成。如果没有,则会根据注册的BeanDefinition所提供的信息实例化被请求对象,并为其注入依赖。当该对象装配完毕后,容器会立即将其返回给请求方法使用。
注入依赖:依赖注入(Dependency Injection)和控制反转(Inversion of Control)是同一个概念。具体含义是:当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,在 传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在Spring里,创建被调用者的工作不再由调用者来完成,因此称为控制反转;创建被调用者 实例的工作通常由Spring容器来完成,然后注入调用者,因此也称为依赖注入
而在实际场景下,我们更多的使用另外一种类型的容器:ApplicationContext,它构建在BeanFactory之上,属于更高级的容器,除了具有BeanFactory的所有能力之外,还提供对事件监听机制以及国际化的支持等。它管理的bean,在容器启动时全部完成初始化和依赖注入操作。
分析spring启动
创建spirngApplication
1. 将主启动类存储到LinkedHashSet
2. 设置启动器
3. 设置监听器
4. 在栈中找到main方法执行
- 设置启动器和设置监听器都是通过SpringFactoriesLoader.loadFactoryNames再找到loadSpringFactories,从"META-INF/spring.factories"加载出类名,再通过反射加载出来的
执行run方法
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
//1.通过SpringFactoriesLoader查找并加载所有的SpringApplicationRunListeners,通过调用
//starting()方法通知所有的SpringApplicationRunListeners:应用开始启动了
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
//2.创建并配置当前应用将要使用的Environment 加载系统配置以及用户的自定义配置
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
//3.打印banner
Banner printedBanner = printBanner(environment);
//4.根据是否是web项目,来创建不同的ApplicationContext 空的IOC 容器
context = createApplicationContext();
//5.创建一系列FailureAnalyzer
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//6.IOC容器的前置处理 调用初始化器 加载启动类,注入容器
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//7.调用ApplicationContext的refresh()方法,刷新容器
refreshContext(context);
// IOC容器的后置处理
afterRefresh(context, applicationArguments);
//8.查找当前context中是否注册有CommandLineRunner和ApplicationRunner,如果有则遍历执行它们。
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, listeners, exceptionReporters, ex);
throw new IllegalStateException(ex);
}
listeners.running(context);
return context;
}
1. 获取并运行启动监听器
SpringApplicationRunListeners listeners = this.getRunListeners(args);
如何获取
loadFactoryNames()方法从spring.factorie获取
SimpleApplicationEventMulticaster将前面的监听器注册进来
这个运行监听器内部有一个事件广播器(SimpleApplicationEventMulticaster
),主要用来广播特定的事件(SpringApplicationEvent
)来触发特定的监听器ApplicationListener
。
EventPublishingRunListener是ApplicationListener的父类
EventPublishingRunListener
中的每个方法用来触发SpringApplicationEvent
中的不同子类。
2. 环境构建
这一步主要用于加载系统配置以及用户的自定义配置(application.properties
),源码如下,在run()
方法中:
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
3. 创建IOC容器
根据webApplicationType
决定创建的类型,很显然,我这里的是servlet
,因此创建的是AnnotationConfigServletWebServerApplicationContext
。
这一步仅仅是创建了
IOC容器
,未有其他操作。
4. IOC容器的前置处理
这一步真是精华了,在刷新容器之前做准备,其中有一个非常关键的操作:调用初始化器,自定义的ApplicationContextInitializer
放在META-INF/spring.factories
中,在此时也是会被调用。并且将启动类注入容器,为后续的自动化配置奠定基础。源码如下:
prepareContext(context, environment, listeners, applicationArguments,printedBanner);
5. 刷新容器
- 刷新容器
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
//调用创建的容器applicationContext中的refresh()方法
((AbstractApplicationContext)applicationContext).refresh();
}
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
/**
* 刷新上下文环境
*/
prepareRefresh();
/**
* 初始化BeanFactory,解析XML,相当于之前的XmlBeanFactory的操作,
*/
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
/**
* 为上下文准备BeanFactory,即对BeanFactory的各种功能进行填充,如常用的注解@Autowired @Qualifier等
* 添加ApplicationContextAwareProcessor处理器
* 在依赖注入忽略实现*Aware的接口,如EnvironmentAware、ApplicationEventPublisherAware等
* 注册依赖,如一个bean的属性中含有ApplicationEventPublisher(beanFactory),则会将beanFactory的实例注入进去
*/
prepareBeanFactory(beanFactory);
try {
/**
* 提供子类覆盖的额外处理,即子类处理自定义的BeanFactoryPostProcess
*/
postProcessBeanFactory(beanFactory);
/**
* 激活各种BeanFactory处理器,包括BeanDefinitionRegistryBeanFactoryPostProcessor和普通的BeanFactoryPostProcessor
* 执行对应的postProcessBeanDefinitionRegistry方法 和 postProcessBeanFactory方法
*/
invokeBeanFactoryPostProcessors(beanFactory);
/**
* 注册拦截Bean创建的Bean处理器,即注册BeanPostProcessor,不是BeanFactoryPostProcessor,注意两者的区别
* 注意,这里仅仅是注册,并不会执行对应的方法,将在bean的实例化时执行对应的方法
*/
registerBeanPostProcessors(beanFactory);
/**
* 初始化上下文中的资源文件,如国际化文件的处理等
*/
initMessageSource();
/**
* 初始化上下文事件广播器,并放入applicatioEventMulticaster,如ApplicationEventPublisher
*/
initApplicationEventMulticaster();
/**
* 给子类扩展初始化其他Bean
*/
onRefresh();
/**
* 在所有bean中查找listener bean,然后注册到广播器中
*/
registerListeners();
/**
* 设置转换器
* 注册一个默认的属性值解析器
* 冻结所有的bean定义,说明注册的bean定义将不能被修改或进一步的处理
* 初始化剩余的非惰性的bean,即初始化非延迟加载的bean
*/
finishBeanFactoryInitialization(beanFactory);
/**
* 通过spring的事件发布机制发布ContextRefreshedEvent事件,以保证对应的监听器做进一步的处理
* 即对那种在spring启动后需要处理的一些类,这些类实现了ApplicationListener<ContextRefreshedEvent>,
* 这里就是要触发这些类的执行(执行onApplicationEvent方法)
* 另外,spring的内置Event有ContextClosedEvent、ContextRefreshedEvent、ContextStartedEvent、ContextStoppedEvent、RequestHandleEvent
* 完成初始化,通知生命周期处理器lifeCycleProcessor刷新过程,同时发出ContextRefreshEvent通知其他人
*/
finishRefresh();
}
finally {
resetCommonCaches();
}
}
}
调用ApplicationContext的refresh()方法,刷新容器
- 这里的刷新和spring中刷新原理类似,这里重点关注invokeBeanFactoryPostProcessors(beanFactory);方法,主要完成获取到所有的BeanFactoryPostProcessor来对容器做一些额外的操作,通过源可以进入到PostProcessorRegistrationDelegate类
的invokeBeanFactoryPostProcessors()方法,会获取类型为BeanDefinitionRegistryPostProcessor的beanorg.springframework.context.annotation.internalConfigurationAnnotationProcessor,对应的Class为ConfigurationClassPostProcessor。ConfigurationClassPostProcessor用于解析处理各种注解,包括:@Configuration、@ComponentScan、@Import、@PropertySource、@ImportResource、@Bean。当处理@import注解的时候,就会调用<自动配置>这一小节中的EnableAutoConfigurationImportSelector.selectImports()来完成自动配置功能
6. IOC容器的后置处理
afterRefresh(context, applicationArguments);
默认为空,如果有自定义需求可以重写,比如打印一些启动结束日志等。
7. 发出结束执行的事件
同样是EventPublishingRunListener
这个监听器,广播ApplicationStartedEvent
事件。
但是这里广播事件和前几次不同,并不是广播给
SpringApplication
中的监听器(在构建过程中从spring.factories
文件获取的监听器)。因此在IOC容器
中注入的监听器(使用@Component
等方式注入的)也能够生效。前面几个事件只有在spring.factories
文件中设置的监听器才会生效。
跟着代码进入,可以看到started()
方法源码如下:
[](https://gitee.com/chenjiabing666/BlogImage/raw/master/Spring Boot 启动流程源码分析/18.png)
这里并没有用事件广播器SimpleApplicationEventMulticaster
广播事件,而是使用ConfigurableApplicationContext
直接在IOC容器
中发布事件。
8. 执行Runners
callRunners(context, applicationArguments);
[外链图片转存中…(img-WegKi546-1627550283767)]