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方法。