springboot启动过程(3)-refresh方法
1 springboot在启动的时候,会调用run方法,创建环境设置spring容器,其中包含refresh方法,完成配置类解析,各种beanFactoryPostProcess和beanPostProcessor注册,web内置容器构造,国际化配置初始化等,refresh调用了父类AbstractApplicationContext的refresh方法如下。
public void refresh() throws BeansException, IllegalStateException {
Object var1 = this.startupShutdownMonitor;
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var9) {
if(this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
(1)prepareRefresh 在rehresh之前做的准备工作,一是设置spring启动事件,开启活跃状态;二是初始化属性源信息;三是验证必要属性。
(2)prepareBeanFactory 从spring容器获取BeanFactory并进行相关设置为后续使用做准备。
*设置用于加载bean的classLoader,设置可以解析bean表达式的表达式解析器,添加属性注册器ResourceEditorRegistrar。
* 添加ApplicationContextAwarePocessor这个BeanPostProcessor,注入ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware、EnvironmentAware几个接口。
* 设置各种bean,BeanFactory,ResourceLoader,ApplicatioinEventPublisher,ApplicationContext。
* 配置默认系统属性等。
(3)postProcessBeanFactory 继上一步beanfactory设置之后进行后续操作,不同spring容器进行不同操作。比如AnnotationConfigEmbeddedWebApplicationContext会对bean进行注入,检查basePackages属性,如果设置了会使用ClassPathBeanDefinitionScanner对basePackage下面的bean进行扫描并注册,如果设置了annotatedClasses属性,就会使用AnnotatedBeanDefinitionReader注册这些带注解的bean。
(4)invokeBeanFactoryPostProcessors
* BeanFactoryPostProcessor 其实现类可以在spring容器加载了bean的定义文件之后,在bean实例化之前执行。接口方法的入参是ConfigurrableListableBeanFactory,使用该参数,可以获取到相关bean的定义信息,修改各种配置的元数据,可以配置多个processor,通过设置order属性来控制各个实现类的执行顺序。
* BeanPostProcessor BeanPostProcessor是在spring容器加载了bean的定义文件并且实例化bean之后执行的。BeanPostProcessor的执行顺序是在BeanFactoryPostProcessor之后,BeanPostProcessor的作用域是容器级的,它只和所在容器有关。如果你在容器中定义了BeanPostProcessor,它仅仅对此容器中的bean进行后置。它不会对定义在另一个容器中的bean进行任何处理。
* BeanDefinitionRegistryPostProcessor:继承BeanFactoryPostProcessor,作用跟BeanFactoryPostProcessor一样,只不过是使用BeanDefinitionRegistry对bean进行处理
基于web程序的Spring容器AnnotationConfigEmbeddedWebApplicationContext构造的时候,会初始化内部属性AnnotatedBeanDefinitionReader reader,这个reader构造的时候会在BeanFactory中注册一些post processor,包括BeanPostProcessor和BeanFactoryPostProcessor(比如ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor);invokeBeanFactoryPostProcessors方法处理BeanFactoryPostProcessor的逻辑是:
从Spring容器中找出BeanDefinitionRegistryPostProcessor类型的bean(这些processor是在容器刚创建的时候通过构造AnnotatedBeanDefinitionReader的时候注册到容器中的),然后按照优先级分别执行,优先级的逻辑如下:
1)实现PriorityOrdered接口的BeanDefinitionRegistryPostProcessor先全部找出来,然后排序后依次执行
2)实现Ordered接口的BeanDefinitionRegistryPostProcessor找出来,然后排序后依次执行
3)没有实现PriorityOrdered和Ordered接口的BeanDefinitionRegistryPostProcessor找出来执行并依次执行
ConfigurationClassPostProcessor这个processor是优先级最高的被执行的processor(实现了PriorityOrdered接口)。这个ConfigurationClassPostProcessor会去BeanFactory中找出所有有@Configuration注解的bean,然后使用ConfigurationClassParser去解析这个类。ConfigurationClassParser内部有个Map类型的configurationClasses属性用于保存解析的类,ConfigurationClass是一个对要解析的配置类的封装,内部存储了配置类的注解信息、被@Bean注解修饰的方法、@ImportResource注解修饰的信息、ImportBeanDefinitionRegistrar等都存储在这个封装类中。这里ConfigurationClassPostProcessor最先被处理还有另外一个原因是如果程序中有自定义的BeanFactoryPostProcessor,那么这个PostProcessor首先得通过ConfigurationClassPostProcessor被解析出来,然后才能被Spring容器找到并执行。(ConfigurationClassPostProcessor不先执行的话,这个Processor是不会被解析的,不会被解析的话也就不会执行了)。
invokeBeanFactoryPostProcessors方法总结来说就是从Spring容器中找出BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor接口的实现类并按照一定的规则顺序进行执行。 其中ConfigurationClassPostProcessor这个BeanDefinitionRegistryPostProcessor优先级最高,它会对项目中的@Configuration注解修饰的类(@Component、@ComponentScan、@Import、@ImportResource修饰的类也会被处理)进行解析,解析完成之后把这些bean注册到BeanFactory中。需要注意的是这个时候注册进来的bean还没有实例化。
(5)registerBeanPostProcessors
使用了PostProcessorRegistrationDelegate类的registerBeanPostProcessors方法执行。这里的过程跟invokeBeanFactoryPostProcessors类似:
1)先找出实现了PriorityOrdered接口的BeanPostProcessor并排序后加到BeanFactory的BeanPostProcessor集合中
2)找出实现了Ordered接口的BeanPostProcessor并排序后加到BeanFactory的BeanPostProcessor集合中
3)没有实现PriorityOrdered和Ordered接口的BeanPostProcessor加到BeanFactory的BeanPostProcessor集合中
这些已经存在的BeanPostProcessor在postProcessBeanFactory方法中已经说明,都是由AnnotationConfigUtils的registerAnnotationConfigProcessors方法注册的。这些BeanPostProcessor包括有AutowiredAnnotationBeanPostProcessor(处理被@Autowired注解修饰的bean并注入)、RequiredAnnotationBeanPostProcessor(处理被@Required注解修饰的方法)、CommonAnnotationBeanPostProcessor(处理@PreDestroy、@PostConstruct、@Resource等多个注解的作用)等。如果是自定义的BeanPostProcessor,已经被ConfigurationClassPostProcessor注册到容器内。
这些BeanPostProcessor会在这个方法内被实例化(通过调用BeanFactory的getBean方法,如果没有找到实例化的类,就会去实例化)。
(6)initMessageSource 初始化国际化属性。
(7)initApplicationEventMulticaster 初始化事件广播器,用于发布事件。EventPublishingRunlistener会监听事件,在run函数之前contextPrepared时候已经注入了。这个时候不需要注册,只要拿到BeanFactory的广播器直接设置到spring容器,如果没有再自己初始化。
(8)onRefresh 不同容器各自实现,比如ConfigEmbeddedWebApplicationContext中会调用createEmbeddedServletContainer方法去创建内置的Servlet容器,目前只支持三种 tomcat,jetty,undertow。
(9)registerListeners 把spring容器内的listener和beanfactory的listener都添加到广播器中。
(10)finishBeanFactoryInitialization 实例化BeanFactory 中已经被注册但是没被实例化的所有实例,懒加载除外。比如invokeBeanFactoryPostProcessors方法中根据各种注解解析出来的类,都会初始化。初始化的过程中各种BeanPostProcessor开始起作用。
(11)finishRefresh 初始化生命周期处理器LifecycleProcessor并调用其onrefresh方法,找到SmartLifecycle接口的所有实现类并调用start方法,发布事件告知listener,如果设置了JMX相关属性,还会调用LiveBeansView的registerApplicationContext方法。
springboot启动过程(3)-refresh方法的更多相关文章
- SpringBoot启动过程原理
最近这两年springboot突然火起来了,那么我们就来看看springboot的运行原理. 一.springboot的三种启动方式: 1.运行带有main方法的2.通过命令 Java -jar命令3 ...
- Spring Boot 学习笔记一(SpringBoot启动过程)
SpringBoot启动 Spring Boot通常有一个名为*Application的入口类,在入口类里有一个main方法,这个main方法其实就是一个标准的java应用的入口方法. 在main方法 ...
- (一)SpringBoot启动过程的分析-启动流程概览
-- 以下内容均基于2.1.8.RELEASE版本 通过粗粒度的分析SpringBoot启动过程中执行的主要操作,可以很容易划分它的大流程,每个流程只关注重要操作为后续深入学习建立一个大纲. 官方示例 ...
- (五)SpringBoot启动过程的分析-刷新ApplicationContext
-- 以下内容均基于2.1.8.RELEASE版本 紧接着上一篇[(四)SpringBoot启动过程的分析-预处理ApplicationContext] (https://www.cnblogs.co ...
- (四)SpringBoot启动过程的分析-预处理ApplicationContext
-- 以下内容均基于2.1.8.RELEASE版本 紧接着上一篇(三)SpringBoot启动过程的分析-创建应用程序上下文,本文将分析上下文创建完毕之后的下一步操作:预处理上下文容器. 预处理上下文 ...
- (三)SpringBoot启动过程的分析-创建应用程序上下文
-- 以下内容均基于2.1.8.RELEASE版本 紧接着上一篇(二)SpringBoot启动过程的分析-环境信息准备,本文将分析环境准备完毕之后的下一步操作:ApplicationContext的创 ...
- SpringBoot启动过程原理(转)
1.1 Springboot启动: @SpringBootApplication public class ServerApplication { public static void main(St ...
- springboot启动过程(1)-初始化
1 springboot启动时,只需要调用一个类前面加了@SpringBootApplication的main函数,执行SpringApplication.run(DemoApplication. ...
- springboot启动过程
使用了很长时间的springboot了,一直都知道它简单易用,简化了框架的搭建过程,但是还是不知道它是如何启动的,今天就跟着springboot的源码,去探探这其中的奥妙 以下是spring应用的启动 ...
随机推荐
- Nomad 了解
Introduction to Nomad Welcome to the intro guide to Nomad! This guide is the best place to start wit ...
- c++中子类转父类,父类转子类
#include <iostream> using namespace std; class Father { public: virtual void show() { cout< ...
- Oracle条件分支查询
Oracle的条件分支查询其实跟java的条件分支语法没啥太大的区别,只不过java多了一个switch关键字而已.看例子: SQL ELSE SUM(t1.TOTALTICKET) END tota ...
- Android 从上层到底层-----hal层
CPU:RK3288 系统:Android 5.1 功能:上层 app 控制 led 亮灭 开发板:Firefly RK3288 led_hal.c path:hardware/rockchip/fi ...
- 如何用TortoiseSVN管理本地文档
1.安装(略) 2.搭建本地SVN版本管理数据库(服务器) (1)在本地磁盘上新建一个目录,例如E:\SVN,用来存储各种需要进行版本管理的文档:接着在该目录下再创建一个新的空目录,例如创建一个E:\ ...
- C# WMP 视频播放
1. C#播放器控件常用的方法介绍 右击工具箱->选择项(I)... -> 显示"选择工具箱项" -> COM组件 -> Windows Media Pla ...
- C++ 新特性-右值引用
作为最重要的一项语言特性,右值引用(rvalue references)被引入到 C++0x中.我们可以通过操作符“&&”来声明一个右值引用,原先在C++中使用“&”操作符声明 ...
- MongoDB day01
MongoDB芒果数据库 数据存储阶段 文件管理阶段(.txt .doc .xlc) 优点:数据可以长期保存:数据有一定格式化规范:可以大量存储:使用简单方便 缺点:数据一致性差:用户查找修改不方便: ...
- 查看Unix/Linux的CPU个数和内存大小,系统位数(转载)
一.AIX 1.查看CPU数: (1) smtctl 从AIX5.3起,对于power5的机器,系统引入了SMT(Simultaneousmulti-threading)的功能,其允许两个处理线程在同 ...
- 关于v$BH
关于v$bh的相关字段值FILE# NUMBER Datafile identifier number (to find the filename, query DBA_DATA_FILES or V ...