Spring源碼深度解析(二)
一. 主要內容
- BeanFactory體系設計
- 核心接口
- BeanDefinition加載流程
- 設計思想總結
二. BeanFactory體系設計
BeanFactory是Spring中十分重要的接口,也是Spring IOC容器的頂級接口。它基於工廠模式,定義了最基本的IOC容器的功能,如獲取Bean實例、查看Bean的類型和查看Bean是否存在等:
在BeanFactory的基礎上擴展了很多接口,每個接口都有各自的功能。BeanFactory的繼承體系如下:
三. 各種BeanFactory
-
ListableBeanFactory:可以根據條件列出Bean的清單
-
AutowireCapableBeanFactory:提供了Bean自動注入的支持。
-
HierarchicalBeanFactory:提供了容器繼承的支持,可以維護一個parentBeanFactory父容器的引用,並通過它獲取到父容器中的Bean。
-
ConfigurableBeanFactory:可對BeanFactory進行各種配置
-
DefaultListableBeanFactory:BeanFactory的默認實現,實現了上述所有接口的功能,是BeanFactory的集大成者。
-
XmlBeanFactory:DefaultListableBeanFactory的子類,繼承了DefaultListableBeanFactory的所有功能,並在此基礎上擴展了XML文件相關的定製化處理。
可以看出,Spring很好地貫徹了面向接口編程的原則,幾乎所有的重要的類上面都定義了接口。而且,通過接口的繼承,可以靈活地擴展出不同功能的接口。
四. 核心接口
-
BeanDefinition:對一個Bean實例的描述,包括其類型、屬性、構造器、依賴等。
之前看過一個比喻:BeanFactory相當於一個汽車製造工廠,Bean對應於工廠中造出的各種車,而BeanDefinition就是每種車的圖紙,描述了車的品牌、型號、所需零件、性能參數等。
-
BeanDefinitionRegistry:BeanDefinition註冊中心,定義了對 BeanDefinition 的各種增刪改操作。
-
AliasRegistry:別名註冊中心。Spring支持爲一個Bean定義多個別名。
-
SingletonBeanRegistry:單例Bean註冊中心。Spring會緩存所有Singleton類型的Bean,每次獲取到的都是同一個。
BeanDefinition在定義了Bean的Scope,常用的有Singleton和Prototype,還可以擴展Scope接口進行自定義。
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON; String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
-
Resource:Spring對底層資源的封裝,抽象了所有Spring內部可以使用到的底層資源,並提供了一些相關的查詢和操作方法
對於不同來源的Resource,Spring都提供了對應的實現類,常用的有文件系統資源FileSystemResource和類路徑資源ClassPathResource等。
五. BeanDefinition加載流程解析
BeanDefinition加載是Spring最重要的一個步驟,只有加載了所有定義的BeanDefinition後,才能根據其創建指定Bean,注入依賴,並完成後續一系列功能。BeanDefinition加載是在容器啓動時自動完成的。
書中以XmlBeanFactory爲例,講解了BeanDefinition的加載和註冊流程。雖然現在都以註解方式定義Bean,XML文件方式很少使用,但兩種方式只是BeanDefinition的來源不同,核心處理流程是類似的,因此仍然以書中的內容爲準。至於註解方式加載BeanDefinition的流程,如果感興趣可以看下AnnotationConfigApplicationContext類。
XmlBeanFactory加載BeanDefinition的流程大致可以分爲三個核心步驟:
- 資源的定位
- 將資源文件的解析爲BeanDefinition集合
- 將解析好的BeanDefinition注入到容器中
六. 資源定位
可以顯式指定BeanDefinition所在資源的位置,如書中代碼所示:
Resource resource = new ClassPathResource("applicationContext.xml");
XmlBeanFactory beanFactory = new XmlBeanFactory(resource);
這樣顯式Resource的方式省去了資源定位的步驟,但是,實際上沒有這麼用的,現在使用的都是ApplicationContext接口,其加載資源的處理在AbstractRefreshableApplicationContext#refreshBeanFactory()中,後面章節有具體敘述。
七. BeanDefinition解析
不管基於何種方式,現在拿到了BeanDefinition所在的資源文件Resource,則創建XmlBeanFactory,執行BeanDefinition解析的工作。
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
//加載配置文件
this.reader.loadBeanDefinitions(resource);
}
XmlBeanFactory在維護了一個XmlBeanDefinitionReader實例,其功能就是從XML配置文件中解析出BeanDefinition。XmlBeanDefinitionReader是BeanDefinitionReader接口的實現類,BeanDefinitionReader接口的作用就是解析BeanDefinition。
解析過程中的核心類:
- XmlBeanFactory:XML形式的Bean工廠。
- XmlBeanDefinitionReader:負責從XML配置文件中讀取BeanDefinition。
- DocumentLoader:專注於XML解析,將執行的XML文件解析成一個Document對象。
- BeanDefinitionDocumentReader:針對DocumentLoader解析好的Document,從中加載出BeanDefinition,並註冊到容器中。
- BeanDefinitionParserDelegate:BeanDefinitionDocumentReader內部維護的委託對象,創建BeanDefinition實例並對其進行包裝。
- BeanDefinitionReaderUtils:最終執行實際的BeanDefinition的註冊。
XmlBeanFactory並沒有自己完成BeanDefinition解析的工作,而是委託給各種不同的類去處理,每個類只關注一項具體的功能,這也是單一職責原則的很好的體現。
加載BeanDefinition流程:
八. BeanDefinition註冊
九. 設計思想總結
-
工廠模式
-
面向接口編程
-
單一職責原則
-
策略模式:BeanDefinitionReader的作用是讀取BeanDefinition。根據BeanDefinition的來源不同,Spring定義了不同的實現類(XmlBeanDefinitionReader、GroovyBeanDefinitionReader、PropertiesBeanDefinitionReader),並在相應的BeanFactory處指定了具體的實現類(XmlBeanFactory指定使用XmlBeanDefinitionReader)。
-
模板方法模式:參見DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions()方法:
protected void doRegisterBeanDefinitions(Element root) { // Any nested <beans> elements will cause recursion in this method. In // order to propagate and preserve <beans> default-* attributes correctly, // keep track of the current (parent) delegate, which may be null. Create // the new (child) delegate with a reference to the parent for fallback purposes, // then ultimately reset this.delegate back to its original (parent) reference. // this behavior emulates a stack of delegates without actually necessitating one. //BeanDefinitionParserDelegate代理對象,主要用於BeanDefinition的解析與註冊 BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createDelegate(getReaderContext(), root, parent); //profile屬性處理,只解析滿足當前profile的BeanDefinition if (this.delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); // We cannot use Profiles.of(...) since profile expressions are not supported // in XML config. See SPR-12458 for details. if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { if (logger.isDebugEnabled()) { logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource()); } return; } } } //解析前置處理,模板方法,留給子類實現 preProcessXml(root); //實際的BeanDefinition解析與註冊 parseBeanDefinitions(root, this.delegate); //解析前置處理,模板方法,留給子類實現 postProcessXml(root); this.delegate = parent; }
在父類方法中定義了方法的整體流程,並給出了核心實現parseBeanDefinitions()。在覈心邏輯的前後,各定義了一個模板方法,交由子類進行定製化的處理。