Spring5原始碼解析系列一——IoC容器核心類圖

為了生活,加油發表於2022-02-15

基本概念梳理

IoC(Inversion of Control,控制反轉)就是把原來程式碼裡需要實現的物件建立、依賴,反轉給容器來幫忙實現。我們需要建立一個容器,同時需要一種描述來讓容器知道要建立的物件與物件的關係。這個描述最具體的表現就是我們所看到的配置檔案。

DI(Dependency Injection,依賴注入)就是指物件被動接受依賴類而不自己主動去找,換句話說,就是指物件不是從容器中查詢它依賴的類,而是在容器例項化物件時主動將它依賴的類注入給它。

撇開Spring原始碼不看,從我們自身的理解出發,如果我們來開發這樣的容器,需要考慮下面幾個問題:

  • 物件與物件的關係怎麼表示?

答案:可以用XML、Properties等語義化的配置檔案來表示。

  • 描述物件關係的檔案存放在哪裡?

答案:可以是Classpath、FileSystem、URL網路資源或者servletContext等。

  • 不同的配置檔案對物件的描述不一樣,如標準的、自定義宣告式的,如何統一?

答案:這就可能在內部需要有一個統一的關於物件的定義,所有外部的描述都必須轉化成統一的描述定義。

  • 如何對不同的配置檔案進行解析?

答案:需要對不同的配置檔案語法採用不同的解析器。

Spring核心容器類圖

1、BeanFactory

Spring中Bean的建立是典型的工廠模式,這一系列的Bean工廠,即IoC容器,為開發者管理物件之間的依賴關係提供了很多便利和基礎服務,在Spring中有許多IoC容器的實現供使用者選擇,其相互關係如下圖所示。

其中,BeanFactory作為最頂層的一個介面類,定義了IoC容器的基本功能範圍,BeanFactory有三個重要的子類:ListableBeanFactory、
HierarchicalBeanFactory和AutowireCapableBeanFactory。但是從類圖中我們可以發現最終的預設實現類是DefaultListableBeanFactory,它實現了所有的介面。那麼為何要定義這麼多層次的介面呢?查閱這些介面的原始碼和說明發現,每個介面都有它的使用場合,主要是為了區分在Spring內部操作過程中物件的傳遞和轉化,對物件的資料訪問所做的限制。

例如,ListableBeanFactory介面表示這些Bean可列表化,而HierarchicalBeanFactory表示這些Bean 是有繼承關係的,也就是每個Bean 可能有父 Bean。AutowireCapableBeanFactory 介面定義Bean的自動裝配規則。這三個介面共同定義了Bean的集合、Bean之間的關係及Bean行為。最基本的IoC容器介面是BeanFactory,來看一下它的原始碼:

檢視程式碼

 package org.springframework.beans.factory;

import org.springframework.beans.BeansException;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;


public interface BeanFactory {

    //對FactoryBean的轉義定義,因為如果使用Bean名字來進行搜尋FactoryBean的話得到的只是工廠生成的物件
	//如果需要得到工廠本身,需要轉義
	String FACTORY_BEAN_PREFIX = "&";


	//根據Bean的名字獲得在IoC容器種的Bean的例項
	Object getBean(String name) throws BeansException;

	//根據Bean的名字和Class型別來得到Bean的例項,同時增加了型別安全驗證機制
	<T> T getBean(String name, Class<T> requiredType) throws BeansException;

	
	Object getBean(String name, Object... args) throws BeansException;

	
	<T> T getBean(Class<T> requiredType) throws BeansException;

	
	<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

	
	<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);

	
	<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);

	//提供對Bean的檢索,看下具備Bean的名字的Bean是否存在於IoC容器中
	boolean containsBean(String name);

	//判斷具備name的Bean是否存在於容器,並且是否是單例
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

	//判斷具備name的Bean是否存在於容器,並且是否是原型
	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

	
	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

	
	boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

	//得到Bean例項的Class型別
	@Nullable
	Class<?> getType(String name) throws NoSuchBeanDefinitionException;

	
	@Nullable
	Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;

	//得到Bean例項在IoC容器中的別名,當然你輸入別名來搜尋,結果原名也會包含其中
	String[] getAliases(String name);

}

從上面可以看出,在BeanFactory裡只對IoC容器的基本行為做了定義,根本不關心你的Bean是如何定義及怎樣載入的。正如我們只關心能從工廠裡得到什麼產品,不關心工廠是怎麼生產這些產品的。要知道工廠是如何產生物件的,我們需要看具體的IoC容器實現,Spring裡面提供了許多IoC容器實現,比如GenericApplicationContext、ClasspathXmlApplicationContext等。

PS:ApplicationContext是Spring提供的一個高階的IoC容器,它除了能夠提供IoC容器的基本功能,還為使用者提供了以下附加服務。

  1. 支援資訊源,可以實現國際化(實現MessageSource介面)。
  2. 訪問資源(實現ResourcePatternResolver介面,後面系列會講到)。
  3. 支援應用事件(實現ApplicationEventPublisher介面)。

2、BeanDifinition

Spring IoC容器管理我們定義的各種Bean物件及其相互關係,Bean物件在Spring實現中是以BeanDefinition來描述的,其繼承體系如下圖所
示。

3、BeanDefinitionReader

Bean的解析過程非常複雜,功能被分得很細,因為這裡需要被擴充套件的地方很多,必須保證足夠的靈活性,以應對可能的變化。Bean的解析
主要就是對Spring配置檔案的解析。這個解析過程主要通過BeanDefinitionReader來完成,看看Spring中BeanDefinitionReader的類結構圖,如下圖所示。

總結

通過前面的分析,我們對Spring框架體系有了一個基本的巨集觀瞭解,希望可以好好理解,最好在腦海中形成畫面,為後面的學習
打下良好的基礎。

相關文章