1. 程式人生 > 其它 >Spring原始碼之容器的功能拓展-ApplicationContext

Spring原始碼之容器的功能拓展-ApplicationContext

目錄

PS * 本文程式碼基本為虛擬碼,註釋為個人理解,水平有限,如有謬誤,感謝指正。

關於spring的容器,除了BeanFactory以及它的預設實現類XmlBeanFactory之外。
Spring還提供了 ApplicationContext ,
它用於對 BeanFactory的拓展。

本文入口:

    ApplicationContext bf = new ClassPathXmlApplicationContext("bean.xml"");

核心程式碼:

	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			
			prepareRefresh();//解析預備 重新整理上下文環境  例如對系統屬性或者環境變數進行校驗和準備
			
			
			//  初始化 beanFactory 並讀取xml  配置檔案 , 此函式過後即擁有了 BeanFactory的全部功能
			//  向下轉型 實際持有 它的子類: DefaultListableBeanFactory 型別的物件
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
			
			
			//  ****####  DefaultListableBeanFactory  <-  beanFactory 
			//  功能拓展 
			//  beanFactory 初始化 <功能填充>  複用 BeanFactory 中的 配置檔案讀取、解析 以及其他功能  
			prepareBeanFactory(beanFactory);
			
			try {
				
				postProcessBeanFactory(beanFactory);//  鉤子函式,由子類實現  後處理器 
				
				
				//  啟用各種 BeanFactory 處理器 
				//  postProcessor  後處理器  
				//  ** 啟用 ** 註冊的 各種  BeanFactoryPostProcessor 
				//  **啟用**  且  **註冊**
				invokeBeanFactoryPostProcessors(beanFactory);
				
				
				//  ** 註冊 **   BeanPostProcessors ,用於攔截 Bean 的建立 
				//  《後處理器》,僅僅註冊,在getBean方法呼叫時才會實際觸發   《不啟用》
				//  因為僅僅註冊,所以不需要考慮 硬編碼方式的後處理器 
				//  對於硬編碼方式的後處理器  僅僅在 getBean時被呼叫 
				registerBeanPostProcessors(beanFactory);
				// 註冊最終呼叫 AbstractBeanFactory.addBeanPostProcessor()
				//  AbstractBeanFactory <==  AbstractAutowireCapableBeanFactory <==  DefaultListableBeanFactory
				
				
				
				//  為上下文初始化message 源 ,即不同語言的訊息體(國際化處理)
				initMessageSource();
				
				//  初始化 應用訊息  廣播器,並放入  "applicationEventMulticaster" bean 中 
				initApplicationEventMulticaster();
				
				//  留個子類來初始化其它的 bean  《鉤子函式》
				onRefresh();
				
				//  在所有註冊的bean中,查詢 Listener-bean ,  註冊到訊息廣播器中
				registerListeners();
				
				//  初始化 非延遲載入單例  
				finishBeanFactoryInitialization(beanFactory);
				
				//  完成重新整理過程,通知生命週期處理器  lifecycleProcessor 重新整理過程 
				//  發出  ContextRefreshEvent 通知別人 
				finishRefresh();
			}
			catch (BeansException ex) {
				destroyBeans();
				cancelRefresh(ex);
				throw ex;
			}
			finally {
				resetCommonCaches();
			}
		}
	}

一、解析預備 重新整理上下文環境 例如對系統屬性或者環境變數進行校驗和準備

  • 定義鉤子函式:initPropertySources() 當需要校驗時由子類實現該方法<模板方法模式>
  • 通過 getEnvironment().validateRequiredProperties() 校驗
protected void prepareRefresh() {

		//  子類實現該函式,並設定需要校驗的 內容
		initPropertySources();//  鉤子函式  初始化上下文環境中的任何佔位符屬性資源
		
		//  驗證需要的屬性檔案是否已經 放入環境中  《《《 initPropertySources 是否完成工作 ??
		getEnvironment().validateRequiredProperties();
	}

二、初始化 BeanFactory 並進行 Xml 配置檔案的讀取

  • 已知的是ApplicationContext 是對BeanFactory的 拓展,經過這一步之後,ApplicationContext 將擁有 BeanFactory 的全部功能;

  • AbstractRefreshableApplicationContext 中 實現的方法 refreshBeanFactory() 會產生一個預設的 DefaultListableBeanFactory 物件,

  • 並載入類的 xml 配置 ,最終 ApplicationContext 將持有該 DefaultListableBeanFactory 物件;因此說它擁有 BeanFactory 的所有功能。

@Override
	protected final void refreshBeanFactory() throws BeansException {
		if (hasBeanFactory()) {//  已有,不再重複該邏輯
			destroyBeans();
			closeBeanFactory();
		}
		try {
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());//  為了序列化指定ID 

			//  定製 beanFactory 包括是否允許覆蓋同名稱不同定義的物件、迴圈依賴  
			//  設定 @AutoWired 和 @Qualifier 的註解解析器 QualifierAnnotationAutowireCandidateResolver 
			customizeBeanFactory(beanFactory);
			//  初始化 DocumentReader 並進行 xml 讀取、解析
			loadBeanDefinitions(beanFactory);//  類 AbstractXmlApplicationContext 提供實現 
			this.beanFactory = beanFactory;//  記錄到全域性變數
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

三、對BeanFactory 各種功能填充

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {

  1. 定製 BeanFactory 設定 beanFactory 的類載入器 為當前的 context的 類載入器

  2. 增加對SpEL 語言的支援

  • 登錄檔達式語言SpEL解析器/處理器, 它主要是在依賴解析注入bean的時候、完成bean的初始化和屬性獲取後的屬性填充的時候呼叫。

  • 例如解析: #{bean.filed}
    loadBean[ BeanFactory.getBean(beanName); ] 過程中的屬性注入注入環節:applyPropertyValues,
    會呼叫方法 BeanDefinitionValueResolver.resolveValueIfNecessary() 解析上述定義的引數

  1. 增加 屬性註冊編輯器
  • 新增預設的propertyEditor,它主要是:對bean的屬性等設定進行管理,的一個工具

例如在 XML 配置中定義

<property name="currentDate">
    <value>2021-05-03</value>
</property>
<property name="name">
    <value>張二狗</value>
</property>

在 bean 中定義:

private Date currentDate; 
private String name;

當spring 進行注入的時候,可以把普通屬性name注入進來,但是卻不能識別bean中定義的Date型別currentDate;
有兩種解決方法:

a. 使用自定義屬性編輯器即可,需要繼承 類: Property|EditorSupport 並重寫 setAsText() 方法;

b. 使用spring 自帶的屬性編輯器:CustomDateEditor,

設定屬性註冊編輯器 AbstractBeanFactory.addPropertyEditorRegistrar();

  • spring自帶屬性編輯器,使用案例詳見: AbstractBeanFactory.initBeanWrapper() -> registerCustomEditors();
    -> ResourceEditorRegistrar.registerCustomEditor() 註冊常用的 屬性編輯器
  1. 增加 ApplicationContextAwareProcessor 處理器,該後處理器用於對 容器的補充/增強,而非普通bean的後處理器

在init-method的前後,將呼叫該處理器的postProcessBeforeInitialization()方法 和postProcessAfterInitialization()方法;

  1. 設定 忽略依賴

當 Spring 將ApplicationContextAwareProcessor 註冊後,在 invokeAwareInterfaces() 方法中 間接呼叫的Aware 類已經不是普通的 bean 了,
如:ResourceLoaderAware,所以需要在spring進行bean的依賴注入的時候忽略掉它們。

  1. 註冊依賴

同樣spring 也提供了 註冊依賴的功能

//  設定幾個忽略自動裝配的特殊規則 
		beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
		beanFactory.registerResolvableDependency(ResourceLoader.class, this);
		beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
		beanFactory.registerResolvableDependency(ApplicationContext.class, this);

當解析到對型別 BeanFactory.class 的依賴時,會直接將它的例項 beanFactory 注入。

四、啟用以及註冊各種 BeanFactoryPostProcessor 後處理器

PostProcessorRegistrationDelegate
        .invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
  • 後處理器的作用範圍是容器級的,僅僅對當前容器中的 bean 生效;

  • 需要啟用 以及 註冊(提取並呼叫)

  • 還需要考慮 各種後處理器是否 實現了排序介面

  • BeanFactoryPostProcessor 可以對 bean 定義的元資料進行處理,
    可以說Spring 容器 允許 BeanFactoryPostProcessor , 在實際例項化任意bean之前讀取配置的元資料並進行處理。

  • 可以分為xml 檔案配置的 BeanFactoryPostProcessor 後處理器 和 硬編碼型別的 BeanFactoryPostProcessor 後處理器。

五、註冊後處理器 BeanPostProcessor

  • 僅僅對 BeanPostProcessor 型別的後處理器進行註冊,實際呼叫發生在 getBean(beanName); 例項化bean的時候

  • 類似對 BeanFactoryPostProcessor 的處理,區別是 BeanPostProcessor 由於只需要註冊不需要啟用,所以它只處理配置檔案中配置的 BeanPostProcessor ,而不處理硬編碼型別的 BeanPostProcessor

後續環節

後續環節還包括:

  • 為上下文初始化message 源 ,即不同語言的訊息體(國際化處理)

  • 初始化 應用訊息 廣播器,並放入 "applicationEventMulticaster" bean 中

  • 在所有註冊的bean中,查詢 Listener-bean , 註冊到訊息廣播器中

  • 初始化 非延遲載入單例

  • 完成重新整理過程,通知生命週期處理器 lifecycleProcessor 重新整理過程

    。。。。 等等

由於邏輯並不複雜,不再記錄。

-- 本文僅為個人學習spring原始碼後的理解。