Spring IoC 源碼閱讀

Spring IOC 總覽

  最近這幾個月的時間一直在看 Spring的源碼,學習的過程自己就是一個輸入輸出,反覆循環的過程,通過這一段時間的學習,從之前只是使用的階段到如今 Spring的理解又有了一些新的認識。經過以後的文章來記錄學習的過程。

  在開始 Spring IoC 以前,先來了解一下 控制反轉依賴倒置的設計思想。java

  控制反轉,是指依賴對象的得到反轉,也就是說這是一個解耦的過程。對象之間的依賴關係管理由具體對象來完成,會致使代碼之間的耦合程度加強。所以對象之間的依賴關係,交由一個地方統管理(Ioc 容器)。git

  依賴倒置,控制反轉將對象之間依賴關係的管理權交了出去,對象不須要本身維護依賴關係,而是經過 IoC 容器來完成。從對象的角度來講,依賴對象的獲取從本身主動區建立,變成從容器中去獲取。github

  控制反轉的實現有不少種方式。常常會聽到依賴查找依賴注入。在Spring中,IoC容器是實現這個模式的載體,依賴注入是主要的實現方式。所謂依賴注入,即組件之間的依賴關係由容器在應用系統運行期來決定,也就是由容器動態地將某種依賴關係的目標對象實例注入到應用系統中的各個關聯的組件之中。在對象生成或者初始化的時候將數據注入到對象中(完成數據的注入),也能夠經過將依賴對象的引用注入到對象的數據域中(經過對象的引用完成方法的調用)。微信

Spring 實現IoC 的思路和方法

 IoC 統一集中處理對象之間的依賴關係。Spring實現IOC的思路是提供一些配置信息用來描述類之間的依賴關係,而後有容器去解析這些配置信息,繼而維護對象之間的依賴關係,前提是對象之間的依賴關係必須在類中定義好。ide

方法:函數

  1. 應用程序中提供類,提供依賴關係(屬性或者構造方法)
  2. 把須要交給容器管理的對象經過配置信息告訴容器(xml,annotation、javaconfig)
  3. 把各個類之間的依賴關係經過配置信息告訴容器

Spring IoC 設計

  Ioc被理解爲一個容器,在Spring中提供了一系列功能不一樣的容器,它們有不一樣的實現,完成不一樣的功能。固然Spring中也提供的最基礎容器,爲IoC容器設定了最基本的功能規範。下面經過IoC接口設計圖來一探究竟。學習

BeanFactory接口設計路徑.jpg ui

IoC接口設計
  上述圖片中標註出兩條BeanFactory接口的設計路徑,一條是藍色線條表示,一條紅色線條表示。

  • 從接口 BeanFactoryHierarchicalBeanFactory,再到 ConfigurableBeanFactory,是一條 BeanFactory 設計路徑。在 BeanFactory 中定義了最基本的 IoC 容器的功能,包含有 getBean() IoC 中最基礎的方法; 在 HierarchicalBeanFactory 中繼承了 BeanFactory 接口,並增長了 getParentBeanFactory()的接口功能,使 BeanFactory 具有了雙親 IoC 容器的管理功能;在 ConfigurableBeanFactory 接口中,定義了一些 BeanFactory的配置功能,好比 setParentBeanFactory() 設置雙親IoC容器,經過 addBeanPostProcessor() 配置 Bean 後置處理器,等等。spa

  • BeanFactoryListableBeanFactory,再到 ApplicationContext。這條路徑是另外一條主要的設計路徑。ListableBeanFactoryHierarchicalBeanFactory 兩個接口鏈接 BeanFactory 接口定義和 ApplicationContext 應用上線文的接口定義。在 ListableBeanFactory 中 細化了許多 BeanFactory 的功能,如 getBeanDefinitionNames() 接口方法;HierarchicalBeanFactory 如上所述。prototype

從上圖中能夠看到 BeanFactory是 IoC 容器的最基本的實現,是全部 IoC 容器實現的基類,其中規範的 IoC 容器 最基本的功能。 反觀 ApplicationContext 是 IoC 容器的一種接口,是 BeanFactory 的子接口,可是他繼承了 ResourcePatternResolverEnvironmentCapableMessageSourceApplicationEventPublisher 接口,在 BeanFactory 的基礎上添加一些功能,使得容器能夠支持一些更高級的特性。

依賴注入的方式

  • 接口注入

  • setter注入

    setter注入也稱設值注入,IoC容器經過成員變量的setter方法來注入被依賴的對象。這種注入方式
    簡單、直觀,於是在Spring的依賴注入中大量使用。
    複製代碼
  • 構造器注入

    經過構造器來完成成員變量的注入,就是驅動Spring在底層以反射的方式執行帶指定參數的構造器,當執行帶
    參數的構造器時,就能夠利用構造器參數對成員變量執行初始化。
    複製代碼

Spring Framework 中,僅使用構造函數setter 注入。下面先對這兩張注入方式作一個簡單的比較。

構造函數注入 setter 注入
沒有部分注入 有部分注入
不會覆蓋 setter 屬性 會覆蓋 setter 屬性
任意修改都會建立一個新實例 任意修改不會建立一個新實例
適用於設置不少屬性 適用於設置少許屬性

   BeanFactorySpring IoC 中最基礎的類,在BeanFactory中提供了最基本的IoC容器的功能,定義了IoC容器最基本的形式,而且提供了IoC 容器所應該遵循的最基本的原則。在Spring中,BeanFactory只是一個接口類,對IoC的基本功能作了封裝。其實現 類,如DefaultListableBeanFactoryXmlBeanFactoryApplicationContext等均可以當作是IoC容器附加某種功能的具體實現。接下來從源碼的角度看看,在這個接口類中都作了什麼:

public interface BeanFactory {

	/** * 使用轉義符"&"來獲得 FactoryBean自己。用來區分經過容器獲取 FactoryBean 產生的對象,和 FactoryBean 自己 * 舉例: * myObject 獲得一個 FactoryBean (產生)修飾的對象 * &myObject 獲得的是 FactoryBean 的工廠,用來產生 FactoryBean 的對象 * 區分 FactoryBean 和 BeanFactory * FactoryBean 是對象,是一個能產生或者修飾對象生成的工廠 Bean * BeanFactory 是對象工廠 也是就 IOC 容器,全部的 Bean 都是由 BeanFactory 進行管理 */
	String FACTORY_BEAN_PREFIX = "&";


	/** * 經過指定的名字獲取Bean */
	Object getBean(String name) throws BeansException;

	/** * 經過Bean的名稱 和 類型 獲取 Bean */
	<T> T getBean(String name, Class<T> requiredType) throws BeansException;

	/** * 經過Bean的名稱 和 構造參數 獲取 Bean */
	Object getBean(String name, Object... args) throws BeansException;

	/** * 經過Bean的類型 */
	<T> T getBean(Class<T> requiredType) throws BeansException;

	/** * 經過Bean的類型 和 構造參數 */
	<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

	/** * 方法用於獲取指定bean的提供者,能夠看到它返回的是一個ObjectProvider,其父級接口是ObjectFactory */
	<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);

	/** * 經過ResolvableType獲取ObjectProvider */
	<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);

	/** * 經過指定的名字判斷 工廠中是否認義 或者 已經註冊了 一個 BeanDefinition */
	boolean containsBean(String name);

	/** * 用來出查詢指定名字的 bean 是不是單例(singleton)的,單例屬性 是在 BeanDefinition 指定的 */
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

	/** * 用來出查詢指定名字的 bean 是不是原型(prototype)的,原型屬性 是在 BeanDefinition 指定的 */
	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

	/** * 判斷指定名字的 Bean 的 Class 類型是不是特定的 Class 類型 */
	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

	/** * 判斷指定名字的 Bean 的 Class 類型是不是特定的 Class 類型 */
	boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

	/** * 查詢指定名字的 Bean 的 Class 類型 */
	@Nullable
	Class<?> getType(String name) throws NoSuchBeanDefinitionException;

	/** * 獲取指定的名字的 Bean 的全部別名,別名是用戶在 BeanDefinition 中本身定義的 */
	String[] getAliases(String name);

}
複製代碼

  BeanFactory接口設計了getBean() 方法,這個方法是IoC容器API的主要方法,經過這個方法, 能夠取得IoC容器中管理的BeanBean的取得是經過指定的名字來索引的。若是須要在獲取Bean的時候對Bean的類型 進行檢查,BeanFactory接口定義了帶有參數的getBean()方法,這個方法的使用與不帶參數的方式相似,不一樣的是增長了對Bean檢索的類型的要求。


我的微信公衆號:

我的github: github.com/FunCheney
相關文章
相關標籤/搜索