1. 程式人生 > >spring framework 4 原始碼閱讀

spring framework 4 原始碼閱讀

前面寫了幾篇spring 的介紹文章,感覺與主題不是很切合。重新整理下思路,從更容易理解的角度來寫下文章。

spring 的骨架

spring 的骨架,也是spring 的核心包。主要包含三個內容 1.context:spring 的上線文-------導演 2.core:spring的核心包,主要包括spring所以用到的工具-------道具 3.beans:spring的bean例項 -------演員


導演負責安排演出,演員負責按照導演的指示來演出,演出過程中需要使用道具。

我想大家看完這些圖片之後就明白大致的包關係了。

spring包結構


大家看到相應包內容。 core包側重於幫助類,操作工具,beans包更側重於bean例項的描述。context更側重全域性控制,功能衍生。 下面我們就針對context和factory對類的關係繼續一個基本概括:

核心類之間的關係

我們先來看下bean包下的beanfactory類,以及抽象類等。
可以看到在介面的實現泛化的過程中,每一個介面在繼承父介面的同時,也繼承了父介面的一些方法。這就可以看出面向介面變成微妙之處。

BeanFactory【所有BeanFactory的父類】


可以看到beanfactory中定義了一些基本方法,包括根據名稱獲取bean例項等。

HierarchicalBeanFactory【層次化的BeanFactory】


可以看到此介面實現了層次化,及獲取beanFactory的父容器

LisableBeanFactory列表式Beanfactory


可以看到為beanfactory設定了列表的功能,並且規劃瞭如何從列表中取出相應的方法的能力。

小結:

從上述類命名以及介面規劃可以看到,通過介面的不斷繼承,beanfactory被不斷的豐富抽象起來。層層細分之後,沒有個類都的職責都變的單一了,同時在擴充套件該的屬性時也變的更加方便。針對原始碼,最好的辦法還是根據名稱來,最方便。

context【上下線文】


可以看到到了context的初始化不同於beanfactory,可以側重於抽象型別,具體的方法實現。 裡面大部分方法使用了模板方法的設計模式,父類呼叫抽象方法,抽象方法在子類中實現,物件的獨立性。 主要分成三種context:XML,Annotation,Groovy針對三種形式。

registry【例項或者bean描述註冊器】


將初始化完成的bean註冊的容器中,針對單例來部分,快取單例例項。針對beanDefinition部分,快取bean描述。

Strategy【初始化策略】


兩種初始化策略 一種是簡單策略,一種是cgilib的策略,當時這裡使用的模式是策略模式。

context的初始化

	/**
	 * 在parent下建立ClassPathXmlApplicaitonContext,
	 * 從XML中讀取所有Bean定義.
	 * @param configLocations 配置檔案路徑如c:\simpleContext.xml
	 * @param refresh 是否需要自動重新整理context,refresh-->重新載入
	 * 載入所有的bean定義,建立所有單例.
	 * refresh為true的時候, 根據context來手工重新整理
	 * @param parent the parent context
	 * @throws BeansException if context creation failed
	 * @see #refresh()
	 */
	public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
			throws BeansException {
		//初始化XmlApplicationContext
		super(parent);
		//轉換配置檔案的路徑
		setConfigLocations(configLocations);
		if (refresh) {
			//重新重新整理原有的context,這一篇的重點
			refresh();
		}
	}

下面我們來看下AbstractApplicationContext.refresh()方法

	//載入或重新整理持久的配置,可能是xml檔案,properties檔案,或者關係型資料庫的概要。
	//做為一個啟動方法,如果初始化失敗將會銷燬已經建立好的單例,避免重複載入配置檔案。
	//換句話說,在執行這個方法之後,要不全部載入單例,要不都不載入
	public void refresh() throws BeansException, IllegalStateException 
	{
		synchronized (this.startupShutdownMonitor) 
		{
			// 初始化配置準備重新整理,驗證環境變數中的一些必選引數
			prepareRefresh();

			// 告訴繼承類銷燬內部的factory建立新的factory的例項
			// 初始化Bean例項
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// 初始化beanFactroy的基本資訊,包括classloader,environment,忽略的註解等
			prepareBeanFactory(beanFactory);

			try {
				// beanfactory內部的postProcess,可以理解為context中PostProcess的補充
				beanFactory.postProcessBeanFactory(beanFactory);

				// 執行BeanFactoryPostProcessor(在beanFactory初始化過程中,bean初始化之前,修改beanfactory引數)、
				// BeanDefinitionRegistryPostProcessor 其實也是繼承自BeanFactoryPostProcessor,
				// 多了對BeanDefinitionRegistry的支援invokeBeanFactoryPostProcessors(beanFactory);
				// 執行postProcess,那BeanPostProcessor是什麼呢,是為了在bean載入過程中修改bean的內容,
				// 使用分的有兩個而方法Before、After分別對應初始化前和初始化後
				registerBeanPostProcessors(beanFactory);

				// 初始化MessageSource,主要用作I18N本地化的內容
				initMessageSource();

				// 初始化事件廣播ApplicationEventMulticaster,使用觀察者模式,對註冊的ApplicationEvent時間進行捕捉
				initApplicationEventMulticaster();

				// 初始化特殊bean的方法
				onRefresh();

				// 將所有ApplicationEventListener註冊到ApplicationEventMulticaster中
				registerListeners();

				// 初始化所有不為lazy-init的bean,singleton例項
				finishBeanFactoryInitialization(beanFactory);

				// 初始化lifecycle的bean並啟動(例如quartz的定時器等),如果開啟JMX則將ApplicationContext註冊到上面
				finishRefresh();
			}
			catch (BeansException ex) 
			{
				//銷燬已經建立單例
				resources.destroyBeans();

				// 將context的狀態轉換為無效,標示初始化失敗
				flag.cancelRefresh(ex);

				// 將異常傳播到呼叫者
				throw ex;
			}
		}
	}
我們從時序圖來看啟動上述初始化(門面模式facade)