Spring源碼系列-容器刷新

Spring對於程序員說來講都不陌生;做爲一個強大的開源技術,幫助咱們可以更好的進行項目的開發與維護。java

上次在Spring的啓動過程文章中對Spring的啓動過程作了一個較爲詳細的說明和分析。那麼在實際的過程當中,Spring的啓動實際上就是Spring容器的初始化過程。本文將從源碼的角度結合本身斷點執行過程當中保留的現場來分析一下容器的刷新過程(主要分析前幾個方法,後面幾個會分開來講)。程序員

Spring的啓動是經過ContextLoaderListener來進行的,在ContextLoaderListener中經過委託父類ContextLoader的initWebApplicationContext來完成具體的初始化過程。具體的啓動過程能夠看下以前的那篇文章。web

在initWebApplicationContext方法是用來建立容器的,核心代碼以下:spring

今天主要來看configureAndRefreshWebApplicationContext方法中最後的wac.refresh()到底發生了哪些事;

一、obtainFreshBeanFactory:BeanFactory的刷新和建立

refresh()方法主要爲IoC容器Bean的生命週期管理提供條件,Spring IoC容器載入Bean定義資源文件從其子類容器的refreshBeanFactory()方法啓動,因此整個refresh()中「ConfigurableListableBeanFactory beanFactory =obtainFreshBeanFactory();」這句之後代碼的都是註冊容器的信息源和生命週期事件,載入過程就是從這句代碼啓動。 AbstractApplicationContext的obtainFreshBeanFactory()方法調用子類容器的refreshBeanFactory()方法,啓動容器載入Bean定義資源文件的過程。 refresh()方法的做用是:在建立IoC容器前,若是已經有容器存在,則須要把已有的容器銷燬和關閉,以保證在refresh以後使用的是新創建起來的IoC容器。refresh的做用相似於對IoC容器的重啓,在新創建好的容器中對容器進行初始化,對Bean定義資源進行載入。 和refreshBeanFactory方法相似,載入Bean定義的方法loadBeanDefinitions也使用了委派模式,在AbstractRefreshableApplicationContext類中只定義了抽象方法,具體的實現調用子類容器中的方法實現。apache

//通知子類去刷新內部bean 工廠tomcat

再來看refreshBeanFactory

此實現執行該上下文的底層bean工廠的實際刷新,關閉之前的bean工廠(若是有的話),併爲上下文生命週期的下一階段初始化一個新的bean工廠。bash

customizeBeanFactory(DefaultListableBeanFactory beanFactory)websocket

/**
        //經過當前上下文來自定義內部bean工廠<br>
	 * Customize the internal bean factory used by this context.
	 * Called for each {@link #refresh()} attempt.
	 * <p>The default implementation applies this context's * {@linkplain #setAllowBeanDefinitionOverriding "allowBeanDefinitionOverriding"} * and {@linkplain #setAllowCircularReferences "allowCircularReferences"} settings, * if specified. Can be overridden in subclasses to customize any of * {@link DefaultListableBeanFactory}'s settings.
	 * @param beanFactory the newly created bean factory for this context
	 * @see DefaultListableBeanFactory#setAllowBeanDefinitionOverriding
	 * @see DefaultListableBeanFactory#setAllowCircularReferences
	 * @see DefaultListableBeanFactory#setAllowRawInjectionDespiteWrapping
	 * @see DefaultListableBeanFactory#setAllowEagerClassLoading
	 */
	protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
		if (this.allowBeanDefinitionOverriding != null) {
			beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		if (this.allowCircularReferences != null) {
			beanFactory.setAllowCircularReferences(this.allowCircularReferences);
		}
	}
複製代碼

XmlWebApplicationContext類中loadBeanDefinitions(beanFactory)session

@Override
	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// Create a new XmlBeanDefinitionReader for the given BeanFactory.
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

		// Configure the bean definition reader with this context's // resource loading environment. beanDefinitionReader.setEnvironment(getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); } 複製代碼

AbstractApplicationContext調用loadBeanDefinitions(DefaultListableBeanFactory beanFactory) ,此方法根據首先建立XmlBeanDefinitionReader對象,而後配置該對象的上下文和資源加載環境,同時調用子類實現的initBeanDefinitionReader對XmlBeanDefinitionReader進行個性化配置,最近後入到initBeanDefinitionReader(beanDefinitionReader)的調用:app

  1. 據給定的BeanFactory建立XmlBeanDefinitionReader 對象
  2. 配置beanDefinitionReader的上下文和資源加載環境
  3. 用子類實現的initBeanDefinitionReader對XmlBeanDefinitionReader進行個性化配置initBeanDefinitionReader(beanDefinitionReader);
  4. 調用載入Bean定義的方法,在當前類中只定義了抽象的loadBeanDefinitions方法,具體的實現調用子類容器

裝載bean定義經過XmlBeanDefinitionReader。

// Create a new XmlBeanDefinitionReader for the given BeanFactory. 經過給定的bean工廠建立一個新的XmlBeanDefinitionReader
1.XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

2.使用上下文的資源加載環境配置bean定義讀取器。
   beanDefinitionReader.setEnvironment(getEnvironment());
   beanDefinitionReader.setResourceLoader(this);
   beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
3.容許子類提供reader的自定義初始化,而後繼續實際加載bean定義。
    //經過制定的XmlBeanDefinitionReader來載入beandefinitionReader 
   initBeanDefinitionReader(beanDefinitionReader)
   // 經過制定的XmlBeanDefinitionReader來載入bean definitions
   loadBeanDefinitions(beanDefinitionReader)
複製代碼

AbstractApplicationContext調用loadBeanDefinitions(beanDefinitionReader),這個方法是取得資源或資源路徑而後經過傳入的reader去加載BeanDefinitions。

二、loadBeanDefinitions

目前使用Spring的配置都是基於XML的,所以使用XmlBeanDefinitionReader 中的loadBeanDefinitions方法。

看doLoadBeanDefinitions,這個就是具體的讀取文件配置,而後註冊成Bean

三、prepareBeanFactory

配置工廠的標準上下文特性,如上下文的類裝載器和後處理器。

  • 告訴內部bean工廠使用上下文的類裝入器等。
  • 上下文回調配置bean工廠。
  • BeanFactory接口未登記爲普通工廠的解析式。MessageSource登記(爲自動裝配建立)做爲一個Bean
  • 若是建立;就去尋找LoadTimeWeaver,而後準備組織
  • 註冊默認環境bean。

經過斷點來看下當前的beanFactory

繼續執行...

beanDefinitionMap

manualSingletonNames

四、postProcessBeanFactory

註冊web特性的全局域

1).registerWebApplicationScopes

註冊具備web特性的域;包括:"request", "session", "globalSession", "application"

看下存儲結構:
registerScope方法
2).registerEnvironmentBeans

註冊web特性 環境bean(「contextparameters」、「ContextAttribute」)與給定的WebApplicationContext使用BeanFactory。

1.servletContext

2.servletConfig
3.registerSingleton

這裏是找到了咱們默認的配置文件參數:
beanName=contextParameters

最後是將contextAttributes放入;contextAttributes中包含的屬性值比較多,具體以下面所示:

主要包括: javax.servlet.context.tempdir, org.apache.catalina.resources, org.springframework.web.context.support.ServletContextScope, org.apache.tomcat.util.scan.MergedWebXml, org.apache.tomcat.InstanceManager, org.apache.catalina.jsp_classpath, javax.websocket.server.ServerContainer, org.apache.tomcat.JarScanner

這裏是把須要的東西所有載入進來了,有不少。就不貼了(mime-mapping)....

五、invokeBeanFactoryPostProcessors

BeanDefinitionRegistryPostProcessor實例化:標準BeanFactoryPostProcessor的擴展,BeanFactoryPostProcessor的做用是用來進一步定義註冊的BeanDefinition,IoC容器本質就是Bean管理,因此BeanFactoryPostProcessor自己也是Bean,要對BeanFactoryPostProcessor的BeanDefinition進一步定義就經過BeanDefinitionRegistryPostProcessor進行註冊,BeanDefinitionRegistryPostProcessor及其子類是Ioc容器最實例化的一類Bean。它們在ConfigurableApplicationContext(ApplicationContext子接口)實現類調用refresh()方法調用invokeBeanFactoryPostProcessors(beanFactory);方法時就被實例化。

OK,今天關於這部分的分析就到此結束了,後面的過程會在下一篇Spring系列文章中繼續來說refresh中的過程。

祝你們平安夜快樂....

若是您對系列文章有任何意見,能夠給我留言,感謝你們。

下面是一個接蘋果的姿式,呼呼呼.....

相關文章
相關標籤/搜索