spring源碼版本5.0.5
Spring容器創建之后,會調用它的refresh方法刷新Spring應用的上下文。
首先整體查看AbstractApplicationContext#refresh源碼
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { //刷新前的預處理; prepareRefresh(); //獲取BeanFactory;默認實現是DefaultListableBeanFactory,在創建容器的時候創建的 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); //BeanFactory的預准備工作(BeanFactory進行一些設置,比如context的類加載器,BeanPostProcessor和XXXAware自動裝配等) prepareBeanFactory(beanFactory); try { //BeanFactory准備工作完成后進行的后置處理工作 postProcessBeanFactory(beanFactory); //執行BeanFactoryPostProcessor的方法; invokeBeanFactoryPostProcessors(beanFactory); //注冊BeanPostProcessor(Bean的后置處理器),在創建bean的前后等執行 registerBeanPostProcessors(beanFactory); //初始化MessageSource組件(做國際化功能;消息綁定,消息解析); initMessageSource(); //初始化事件派發器 initApplicationEventMulticaster(); //子類重寫這個方法,在容器刷新的時候可以自定義邏輯;如創建Tomcat,Jetty等WEB服務器 onRefresh(); //注冊應用的監聽器。就是注冊實現了ApplicationListener接口的監聽器bean,這些監聽器是注冊到ApplicationEventMulticaster中的 registerListeners(); //初始化所有剩下的非懶加載的單例bean finishBeanFactoryInitialization(beanFactory); //完成context的刷新。主要是調用LifecycleProcessor的onRefresh()方法,並且發布事件(ContextRefreshedEvent) finishRefresh(); } ...... }
prepareRefresh方法
表示在真正做refresh操作之前需要准備做的事情:
- 設置Spring容器的啟動時間,
- 開啟活躍狀態,撤銷關閉狀態,。
- 初始化context environment(上下文環境)中的占位符屬性來源。
- 驗證環境信息里一些必須存在的屬性
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory()
讓這個類(AbstractApplicationContext)的子類刷新內部bean工廠。
- AbstractRefreshableApplicationContext容器:實際上就是重新創建一個bean工廠,並設置工廠的一些屬性。
- GenericApplicationContext容器:獲取創建容器的就創建的bean工廠,並且設置工廠的ID.
prepareBeanFactory方法
上一步已經把工廠建好了,但是還不能投入使用,因為工廠里什么都沒有,還需要配置一些東西。看看這個方法的注釋
/** * Configure the factory's standard context characteristics, * such as the context's ClassLoader and post-processors. * @param beanFactory the BeanFactory to configure */
他說配置這個工廠的標准環境,比如context的類加載器和post-processors后處理器。
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { //設置BeanFactory的類加載器 beanFactory.setBeanClassLoader(getClassLoader()); //設置支持表達式解析器 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); //添加部分BeanPostProcessor【ApplicationContextAwareProcessor】 beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); //設置忽略的自動裝配的接口EnvironmentAware、EmbeddedValueResolverAware、xx,因為ApplicationContextAwareProcessor#invokeAwareInterfaces已經把這5個接口的實現工作做了 beanFactory.ignoreDependencyInterface(EnvironmentAware.class); beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); //注冊可以解析的自動裝配;我們能直接在任何組件中自動注入:BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext //其他組件中可以通過 @autowired 直接注冊使用 beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this); //添加BeanPostProcessor【ApplicationListenerDetector】后置處理器,在bean初始化前后的一些工作 beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); // Detect a LoadTimeWeaver and prepare for weaving, if found. if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); // Set a temporary ClassLoader for type matching. beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } //給BeanFactory中注冊一些能用的組件; if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) { //環境信息ConfigurableEnvironment beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); } if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) { //系統屬性,systemProperties【Map<String, Object>】 beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties()); } if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) { //系統環境變量systemEnvironment【Map<String, Object>】 beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment()); } }
postProcessBeanFactory方法
上面對bean工廠進行了許多配置,現在需要對bean工廠進行一些處理。不同的Spring容器做不同的操作。比如GenericWebApplicationContext容器的操作會在BeanFactory中添加ServletContextAwareProcessor用於處理ServletContextAware類型的bean初始化的時候調用setServletContext或者setServletConfig方法(跟ApplicationContextAwareProcessor原理一樣)。
GenericWebApplicationContext#postProcessBeanFactory源碼:
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { if (this.servletContext != null) { beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext)); beanFactory.ignoreDependencyInterface(ServletContextAware.class); } WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext); WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext); }
AnnotationConfigServletWebServerApplicationContext#postProcessBeanFactory方法
@Override protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { super.postProcessBeanFactory(beanFactory); // 查看basePackages屬性,如果設置了會使用ClassPathBeanDefinitionScanner去掃描basePackages包下的bean並注冊 if (this.basePackages != null && this.basePackages.length > 0) { this.scanner.scan(this.basePackages); } // 查看annotatedClasses屬性,如果設置了會使用AnnotatedBeanDefinitionReader去注冊這些bean if (!this.annotatedClasses.isEmpty()) { this.reader.register(ClassUtils.toClassArray(this.annotatedClasses)); } }
invokeBeanFactoryPostProcessors方法
先介紹兩個接口:
- BeanFactoryPostProcessor:用來修改Spring容器中已經存在的bean的定義,使用ConfigurableListableBeanFactory對bean進行處理
- BeanDefinitionRegistryPostProcessor:繼承BeanFactoryPostProcessor,作用跟BeanFactoryPostProcessor一樣,只不過是使用BeanDefinitionRegistry對bean進行處理
在Spring容器中找出實現了BeanFactoryPostProcessor接口的processor並執行。Spring容器會委托給PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors方法執行。
注
1.在springboot的web程序初始化AnnotationConfigServletWebServerApplicationContext容器時,會初始化內部屬性AnnotatedBeanDefinitionReader reader,這個reader構造的時候會在BeanFactory中注冊一些post processor,包括BeanPostProcessor和BeanFactoryPostProcessor(比如ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor):
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
2.在使用mybatis時,一般配置了MapperScannerConfigurer的bean,這個bean就是繼承的BeanDefinitionRegistryPostProcessor,所以也是這個地方把掃描的mybatis的接口注冊到容器中的。
invokeBeanFactoryPostProcessors方法處理BeanFactoryPostProcessor的邏輯如下:
從Spring容器中找出BeanDefinitionRegistryPostProcessor類型的bean(這些processor是在容器剛創建的時候通過構造AnnotatedBeanDefinitionReader的時候注冊到容器中的),然后按照優先級分別執行,優先級的邏輯如下:
- 實現PriorityOrdered接口的BeanDefinitionRegistryPostProcessor先全部找出來,然后排序后依次執行
- 實現Ordered接口的BeanDefinitionRegistryPostProcessor找出來,然后排序后依次執行
- 沒有實現PriorityOrdered和Ordered接口的BeanDefinitionRegistryPostProcessor找出來執行並依次執行
接下來從Spring容器內查找BeanFactoryPostProcessor接口的實現類,然后執行(如果processor已經執行過,則忽略),這里的查找規則跟上面查找BeanDefinitionRegistryPostProcessor一樣,先找PriorityOrdered,然后是Ordered,最后是兩者都沒。
這里需要說明的是ConfigurationClassPostProcessor這個processor是優先級最高的被執行的processor(實現了PriorityOrdered接口)。這個ConfigurationClassPostProcessor會去BeanFactory中找出所有有@Configuration注解的bean,然后使用ConfigurationClassParser去解析這個類。ConfigurationClassParser內部有個Map<ConfigurationClass, ConfigurationClass>類型的configurationClasses屬性用於保存解析的類,ConfigurationClass是一個對要解析的配置類的封裝,內部存儲了配置類的注解信息、被@Bean注解修飾的方法、@ImportResource注解修飾的信息、ImportBeanDefinitionRegistrar等都存儲在這個封裝類中。
這里ConfigurationClassPostProcessor最先被處理還有另外一個原因是如果程序中有自定義的BeanFactoryPostProcessor,那么這個PostProcessor首先得通過ConfigurationClassPostProcessor被解析出來,然后才能被Spring容器找到並執行。(ConfigurationClassPostProcessor不先執行的話,這個Processor是不會被解析的,不會被解析的話也就不會執行了)。
- 處理@PropertySources注解:進行一些配置信息的解析
- 處理@ComponentScan注解:使用ComponentScanAnnotationParser掃描basePackage下的需要解析的類(@SpringBootApplication注解也包括了@ComponentScan注解,只不過basePackages是空的,空的話會去獲取當前@Configuration修飾的類所在的包),並注冊到BeanFactory中(這個時候bean並沒有進行實例化,而是進行了注冊。具體的實例化在finishBeanFactoryInitialization方法中執行)。對於掃描出來的類,遞歸解析
- 處理@Import注解:先遞歸找出所有的注解,然后再過濾出只有@Import注解的類,得到@Import注解的值。比如查找@SpringBootApplication注解的@Import注解數據的話,首先發現@SpringBootApplication不是一個@Import注解,然后遞歸調用修飾了@SpringBootApplication的注解,發現有個@EnableAutoConfiguration注解,再次遞歸發現被@Import(EnableAutoConfigurationImportSelector.class)修飾,還有@AutoConfigurationPackage注解修飾,再次遞歸@AutoConfigurationPackage注解,發現被@Import(AutoConfigurationPackages.Registrar.class)注解修飾,所以@SpringBootApplication注解對應的@Import注解有2個,分別是@Import(AutoConfigurationPackages.Registrar.class)和@Import(EnableAutoConfigurationImportSelector.class)。找出所有的@Import注解之后,開始處理邏輯:
- 遍歷這些@Import注解內部的屬性類集合
- 如果這個類是個ImportSelector接口的實現類,實例化這個ImportSelector,如果這個類也是DeferredImportSelector接口的實現類,那么加入ConfigurationClassParser的deferredImportSelectors屬性中讓第6步處理。否則調用ImportSelector的selectImports方法得到需要Import的類,然后對這些類遞歸做@Import注解的處理
- 如果這個類是ImportBeanDefinitionRegistrar接口的實現類,設置到配置類的importBeanDefinitionRegistrars屬性中
- 其它情況下把這個類入隊到ConfigurationClassParser的importStack(隊列)屬性中,然后把這個類當成是@Configuration注解修飾的類遞歸重頭開始解析這個類
- 處理@ImportResource注解:獲取@ImportResource注解的locations屬性,得到資源文件的地址信息。然后遍歷這些資源文件並把它們添加到配置類的importedResources屬性中
- 處理@Bean注解:獲取被@Bean注解修飾的方法,然后添加到配置類的beanMethods屬性中
- 處理DeferredImportSelector:處理第3步@Import注解產生的DeferredImportSelector,進行selectImports方法的調用找出需要import的類,然后再調用第3步相同的處理邏輯處理
這里@SpringBootApplication注解被@EnableAutoConfiguration修飾,@EnableAutoConfiguration注解被@Import(EnableAutoConfigurationImportSelector.class)修飾,所以在第3步會找出這個@Import修飾的類EnableAutoConfigurationImportSelector,這個類剛好實現了DeferredImportSelector接口,接着就會在第6步被執行。第6步selectImport得到的類就是自動化配置類。
EnableAutoConfigurationImportSelector的selectImport方法會在spring-boot-autoconfigure包的META-INF里面的spring.factories文件中找出key為org.springframework.boot.autoconfigure.EnableAutoConfiguration對應的值,有109個,這109個就是所謂的自動化配置類(XXXAutoConfiguration)。(如果引入了mybatis和pagehelper,也會在對應的XXXautoconfigure包的META-INF里面的spring.factories找到EnableAutoConfiguration,這樣可能最后得到的自動配置類會大於109個。)然后在過濾排除一下不需要的配置,最后返回實際用到的。
ConfigurationClassParser解析完成之后,被解析出來的類會放到configurationClasses屬性中。然后使用ConfigurationClassBeanDefinitionReader去解析這些類。
這個時候這些bean只是被加載到了Spring容器中。下面這段代碼是ConfigurationClassBeanDefinitionReader的解析bean過程:這個時候這些bean只是被加載到了Spring容器中。下面這段代碼是ConfigurationClassBeanDefinitionReader#loadBeanDefinitions的解析bean過程:
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) { TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator(); for (ConfigurationClass configClass : configurationModel) { //對每一個配置類,調用loadBeanDefinitionsForConfigurationClass方法 loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator); } }
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) { //使用條件注解判斷是否需要跳過這個配置類 if (trackedConditionEvaluator.shouldSkip(configClass)) { //跳過配置類的話在Spring容器中移除bean的注冊 String beanName = configClass.getBeanName(); if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) { this.registry.removeBeanDefinition(beanName); } this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName()); return; } if (configClass.isImported()) { //如果自身是被@Import注釋所import的,注冊自己 registerBeanDefinitionForImportedConfigurationClass(configClass); } //注冊方法中被@Bean注解修飾的bean for (BeanMethod beanMethod : configClass.getBeanMethods()) { loadBeanDefinitionsForBeanMethod(beanMethod); } //注冊@ImportResource注解注釋的資源文件中的bean loadBeanDefinitionsFromImportedResources(configClass.getImportedResources()); //注冊@Import注解中的ImportBeanDefinitionRegistrar接口的registerBeanDefinitions loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); }
invokeBeanFactoryPostProcessors方法總結來說就是從Spring容器中找出BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor接口的實現類並按照一定的規則順序進行執行。 其中ConfigurationClassPostProcessor這個BeanDefinitionRegistryPostProcessor優先級最高,它會對項目中的@Configuration注解修飾的類(@Component、@ComponentScan、@Import、@ImportResource修飾的類也會被處理)進行解析,解析完成之后把這些bean注冊到BeanFactory中。需要注意的是這個時候注冊進來的bean還沒有實例化。
下面這圖就是對ConfigurationClassPostProcessor后置器的總結:
registerBeanPostProcessors方法
從Spring容器中找出的BeanPostProcessor接口的bean,並設置到BeanFactory的屬性中。之后bean被實例化的時候會調用這個BeanPostProcessor。
該方法委托給了PostProcessorRegistrationDelegate類的registerBeanPostProcessors方法執行。這里的過程跟invokeBeanFactoryPostProcessors類似:
- 先找出實現了PriorityOrdered接口的BeanPostProcessor並排序后加到BeanFactory的BeanPostProcessor集合中
- 找出實現了Ordered接口的BeanPostProcessor並排序后加到BeanFactory的BeanPostProcessor集合中
- 沒有實現PriorityOrdered和Ordered接口的BeanPostProcessor加到BeanFactory的BeanPostProcessor集合中
這些已經存在的BeanPostProcessor在postProcessBeanFactory方法中已經說明,都是由AnnotationConfigUtils的registerAnnotationConfigProcessors方法注冊的。這些BeanPostProcessor包括有AutowiredAnnotationBeanPostProcessor(處理被@Autowired注解修飾的bean並注入)、RequiredAnnotationBeanPostProcessor(處理被@Required注解修飾的方法)、CommonAnnotationBeanPostProcessor(處理@PreDestroy、@PostConstruct、@Resource等多個注解的作用)等。
如果是自定義的BeanPostProcessor,已經被ConfigurationClassPostProcessor注冊到容器內。
這些BeanPostProcessor會在這個方法內被實例化(通過調用BeanFactory的getBean方法,如果沒有找到實例化的類,就會去實例化)。
initMessageSource方法
初始化MessageSource組件(做國際化功能;消息綁定,消息解析),這個接口提供了消息處理功能。主要用於國際化/i18n。
initApplicationEventMulticaster方法
在Spring容器中初始化事件廣播器,事件廣播器用於事件的發布。
程序首先會檢查bean工廠中是否有bean的名字和這個常量(applicationEventMulticaster)相同的,如果沒有則說明沒有那么就使用默認的ApplicationEventMulticaster 的實現:SimpleApplicationEventMulticaster
onRefresh方法
一個模板方法,不同的Spring容器做不同的事情。
比如web程序的容器ServletWebServerApplicationContext中會調用createWebServer方法去創建內置的Servlet容器。
目前SpringBoot只支持3種內置的Servlet容器:
- Tomcat
- Jetty
- Undertow
registerListeners方法
注冊應用的監聽器。就是注冊實現了ApplicationListener接口的監聽器bean,這些監聽器是注冊到ApplicationEventMulticaster中的。這不會影響到其它監聽器bean。在注冊完以后,還會將其前期的事件發布給相匹配的監聽器。
protected void registerListeners() { //1、從容器中拿到所有已經創建的ApplicationListener for (ApplicationListener<?> listener : getApplicationListeners()) { //2、將每個監聽器添加到事件派發器中; getApplicationEventMulticaster().addApplicationListener(listener); } // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let post-processors apply to them! // 1.獲取所有還沒有創建的ApplicationListener String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); for (String listenerBeanName : listenerBeanNames) { //2、將每個監聽器添加到事件派發器中; getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); } // earlyApplicationEvents 中保存之前的事件, Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents; this.earlyApplicationEvents = null; if (earlyEventsToProcess != null) { for (ApplicationEvent earlyEvent : earlyEventsToProcess) { //3、派發之前步驟產生的事件; getApplicationEventMulticaster().multicastEvent(earlyEvent); } } }
finishBeanFactoryInitialization方法
實例化BeanFactory中已經被注冊但是未實例化的所有實例(懶加載的不需要實例化)。
比如invokeBeanFactoryPostProcessors方法中根據各種注解解析出來的類,在這個時候都會被初始化。
實例化的過程各種BeanPostProcessor開始起作用。
后面在詳細分析此步驟
finishRefresh方法
refresh做完之后需要做的其他事情。
- 初始化生命周期處理器,並設置到Spring容器中(LifecycleProcessor)
- 調用生命周期處理器的onRefresh方法,這個方法會找出Spring容器中實現了SmartLifecycle接口的類並進行start方法的調用
- 發布ContextRefreshedEvent事件告知對應的ApplicationListener進行響應的操作
如果是web容器ServletWebServerApplicationContext還會啟動web服務和發布消息
protected void finishRefresh() { super.finishRefresh(); WebServer webServer = startWebServer(); if (webServer != null) { publishEvent(new ServletWebServerInitializedEvent(webServer, this)); } }