您好,登錄后才能下訂單哦!
Spring 最重要的概念是 IOC 和 AOP,本篇文章其實(shí)就是要帶領(lǐng)大家來分析下 Spring 的 IOC 容器。既然大家平時(shí)都要用到 Spring,怎么可以不好好了解 Spring 呢?閱讀本文并不能讓你成為 Spring 專家,不過一定有助于大家理解 Spring 的很多概念,幫助大家排查應(yīng)用中和 Spring 相關(guān)的一些問題。
本文采用的源碼版本是 4.3.11.RELEASE,算是 5.0.x 前比較新的版本了。為了降低難度,本文所說的所有的內(nèi)容都是基于 xml 的配置的方式,實(shí)際使用已經(jīng)很少人這么做了,至少不是純 xml 配置,不過從理解源碼的角度來看用這種方式來說無疑是最合適的。
閱讀建議:讀者至少需要知道怎么配置 Spring,了解 Spring 中的各種概念,少部分內(nèi)容我還假設(shè)讀者使用過 SpringMVC。本文要說的 IOC 總體來說有兩處地方最重要,一個(gè)是創(chuàng)建 Bean 容器,一個(gè)是初始化 Bean,如果讀者覺得一次性看完本文壓力有點(diǎn)大,那么可以按這個(gè)思路分兩次消化。讀者不一定對(duì) Spring 容器的源碼感興趣,也許附錄部分介紹的知識(shí)對(duì)讀者有些許作用。
希望通過本文可以讓讀者不懼怕閱讀 Spring 源碼,也希望大家能反饋表述錯(cuò)誤或不合理的地方。
目錄
先看下最基本的啟動(dòng) Spring 容器的例子:
public?static?void?main(String[]?args)?{ ????ApplicationContext?context?=?new?ClassPathXmlApplicationContext("classpath:applicationfile.xml"); }
以上代碼就可以利用配置文件來啟動(dòng)一個(gè) Spring 容器了,請(qǐng)使用 maven 的小伙伴直接在 dependencies 中加上以下依賴即可,個(gè)人比較反對(duì)那些不知道要添加什么依賴,然后把 Spring 的所有相關(guān)的東西都加進(jìn)來的方式。
<dependency> ??<groupId>org.springframework</groupId> ??<artifactId>spring-context</artifactId> ??<version>4.3.11.RELEASE</version></dependency>
spring-context 會(huì)自動(dòng)將 spring-core、spring-beans、spring-aop、spring-expression 這幾個(gè)基礎(chǔ) jar 包帶進(jìn)來。
多說一句,很多開發(fā)者入門就直接接觸的 SpringMVC,對(duì) Spring 其實(shí)不是很了解,Spring 是漸進(jìn)式的工具,并不具有很強(qiáng)的侵入性,它的模塊也劃分得很合理,即使你的應(yīng)用不是 web 應(yīng)用,或者之前完全沒有使用到 Spring,而你就想用 Spring 的依賴注入這個(gè)功能,其實(shí)完全是可以的,它的引入不會(huì)對(duì)其他的組件產(chǎn)生沖突。
廢話說完,我們繼續(xù)。ApplicationContext context = new ClassPathXmlApplicationContext(...)
?其實(shí)很好理解,從名字上就可以猜出一二,就是在 ClassPath 中尋找 xml 配置文件,根據(jù) xml 文件內(nèi)容來構(gòu)建 ApplicationContext。當(dāng)然,除了 ClassPathXmlApplicationContext 以外,我們也還有其他構(gòu)建 ApplicationContext 的方案可供選擇,我們先來看看大體的繼承結(jié)構(gòu)是怎么樣的:
讀者可以大致看一下類名,源碼分析的時(shí)候不至于找不著看哪個(gè)類,因?yàn)?Spring 為了適應(yīng)各種使用場景,提供的各個(gè)接口都可能有很多的實(shí)現(xiàn)類。對(duì)于我們來說,就是揪著一個(gè)完整的分支看完。
當(dāng)然,讀本文的時(shí)候讀者也不必太擔(dān)心,每個(gè)代碼塊分析的時(shí)候,我都會(huì)告訴讀者我們?cè)谡f哪個(gè)類第幾行。
我們可以看到,ClassPathXmlApplicationContext 兜兜轉(zhuǎn)轉(zhuǎn)了好久才到 ApplicationContext 接口,同樣的,我們也可以使用綠顏色的?FileSystemXmlApplicationContext?和?AnnotationConfigApplicationContext?這兩個(gè)類。
FileSystemXmlApplicationContext?的構(gòu)造函數(shù)需要一個(gè) xml 配置文件在系統(tǒng)中的路徑,其他和 ClassPathXmlApplicationContext 基本上一樣。
AnnotationConfigApplicationContext?是基于注解來使用的,它不需要配置文件,采用 java 配置類和各種注解來配置,是比較簡單的方式,也是大勢所趨吧。
不過本文旨在幫助大家理解整個(gè)構(gòu)建流程,所以決定使用 ClassPathXmlApplicationContext 進(jìn)行分析。
我們先來一個(gè)簡單的例子來看看怎么實(shí)例化 ApplicationContext。
首先,定義一個(gè)接口:
public?interface?MessageService?{????String?getMessage(); }
定義接口實(shí)現(xiàn)類:
public?class?MessageServiceImpl?implements?MessageService?{????public?String?getMessage()?{????????return?"hello?world"; ????} }
接下來,我們?cè)?resources?目錄新建一個(gè)配置文件,文件名隨意,通常叫 application.xml 或 application-xxx.xml 就可以了:
<?xml?version="1.0"?encoding="UTF-8"??><beans?xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ???????xmlns="http://www.springframework.org/schema/beans" ???????xsi:schemaLocation="http://www.springframework.org/schema/beans?http://www.springframework.org/schema/beans/spring-beans.xsd"?default-autowire="byName"> ????<bean?id="messageService"?class="com.javadoop.example.MessageServiceImpl"/></beans>
這樣,我們就可以跑起來了:
public?class?App?{????public?static?void?main(String[]?args)?{????????//?用我們的配置文件來啟動(dòng)一個(gè)?ApplicationContext ????????ApplicationContext?context?=?new?ClassPathXmlApplicationContext("classpath:application.xml"); ????????System.out.println("context?啟動(dòng)成功");????????//?從?context?中取出我們的?Bean,而不是用?new?MessageServiceImpl()?這種方式 ????????MessageService?messageService?=?context.getBean(MessageService.class);????????//?這句將輸出:?hello?world ????????System.out.println(messageService.getMessage()); ????} }
以上例子很簡單,不過也夠引出本文的主題了,就是怎么樣通過配置文件來啟動(dòng) Spring 的 ApplicationContext?也就是我們今天要分析的 IOC 的核心了。ApplicationContext 啟動(dòng)過程中,會(huì)負(fù)責(zé)創(chuàng)建實(shí)例 Bean,往各個(gè) Bean 中注入依賴等。
BeanFactory,從名字上也很好理解,生產(chǎn) bean 的工廠,它負(fù)責(zé)生產(chǎn)和管理各個(gè) bean 實(shí)例。
初學(xué)者可別以為我之前說那么多和 BeanFactory 無關(guān),前面說的 ApplicationContext 其實(shí)就是一個(gè) BeanFactory。我們來看下和 BeanFactory 接口相關(guān)的主要的繼承結(jié)構(gòu):
我想,大家看完這個(gè)圖以后,可能就不是很開心了。ApplicationContext 往下的繼承結(jié)構(gòu)前面一張圖說過了,這里就不重復(fù)了。這張圖呢,背下來肯定是不需要的,有幾個(gè)重點(diǎn)和大家說明下就好。
ApplicationContext 繼承了 ListableBeanFactory,這個(gè) Listable 的意思就是,通過這個(gè)接口,我們可以獲取多個(gè) Bean,大家看源碼會(huì)發(fā)現(xiàn),最頂層 BeanFactory 接口的方法都是獲取單個(gè) Bean 的。
ApplicationContext 繼承了 HierarchicalBeanFactory,Hierarchical 單詞本身已經(jīng)能說明問題了,也就是說我們可以在應(yīng)用中起多個(gè) BeanFactory,然后可以將各個(gè) BeanFactory 設(shè)置為父子關(guān)系。
AutowireCapableBeanFactory 這個(gè)名字中的 Autowire 大家都非常熟悉,它就是用來自動(dòng)裝配 Bean 用的,但是仔細(xì)看上圖,ApplicationContext 并沒有繼承它,不過不用擔(dān)心,不使用繼承,不代表不可以使用組合,如果你看到 ApplicationContext 接口定義中的最后一個(gè)方法 getAutowireCapableBeanFactory() 就知道了。
ConfigurableListableBeanFactory 也是一個(gè)特殊的接口,看圖,特殊之處在于它繼承了第二層所有的三個(gè)接口,而 ApplicationContext 沒有。這點(diǎn)之后會(huì)用到。
請(qǐng)先不用花時(shí)間在其他的接口和類上,先理解我說的這幾點(diǎn)就可以了。
然后,請(qǐng)讀者打開編輯器,翻一下 BeanFactory、ListableBeanFactory、HierarchicalBeanFactory、AutowireCapableBeanFactory、ApplicationContext 這幾個(gè)接口的代碼,大概看一下各個(gè)接口中的方法,大家心里要有底,限于篇幅,我就不貼代碼介紹了。
下面將會(huì)是冗長的代碼分析,記住,一定要自己打開源碼來看,不然純看是很累的。
第一步,我們肯定要從 ClassPathXmlApplicationContext 的構(gòu)造方法說起。
public?class?ClassPathXmlApplicationContext?extends?AbstractXmlApplicationContext?{??private?Resource[]?configResources;??//?如果已經(jīng)有?ApplicationContext?并需要配置成父子關(guān)系,那么調(diào)用這個(gè)構(gòu)造方法 ??public?ClassPathXmlApplicationContext(ApplicationContext?parent)?{????super(parent); ??} ??...??public?ClassPathXmlApplicationContext(String[]?configLocations,?boolean?refresh,?ApplicationContext?parent) ??????throws?BeansException?{????super(parent);????//?根據(jù)提供的路徑,處理成配置文件數(shù)組(以分號(hào)、逗號(hào)、空格、tab、換行符分割) ????setConfigLocations(configLocations);????if?(refresh)?{ ??????refresh();?//?核心方法 ????} ??} ????... }
接下來,就是 refresh(),這里簡單說下為什么是 refresh(),而不是 init() 這種名字的方法。因?yàn)?ApplicationContext 建立起來以后,其實(shí)我們是可以通過調(diào)用 refresh() 這個(gè)方法重建的,refresh() 會(huì)將原來的 ApplicationContext 銷毀,然后再重新執(zhí)行一次初始化操作。
往下看,refresh() 方法里面調(diào)用了那么多方法,就知道肯定不簡單了,請(qǐng)讀者先看個(gè)大概,細(xì)節(jié)之后會(huì)詳細(xì)說。
@Overridepublic?void?refresh()?throws?BeansException,?IllegalStateException?{???//?來個(gè)鎖,不然?refresh()?還沒結(jié)束,你又來個(gè)啟動(dòng)或銷毀容器的操作,那不就亂套了嘛 ???synchronized?(this.startupShutdownMonitor)?{??????//?準(zhǔn)備工作,記錄下容器的啟動(dòng)時(shí)間、標(biāo)記“已啟動(dòng)”狀態(tài)、處理配置文件中的占位符 ??????prepareRefresh();??????//?這步比較關(guān)鍵,這步完成后,配置文件就會(huì)解析成一個(gè)個(gè)?Bean?定義,注冊(cè)到?BeanFactory?中, ??????//?當(dāng)然,這里說的?Bean?還沒有初始化,只是配置信息都提取出來了, ??????//?注冊(cè)也只是將這些信息都保存到了注冊(cè)中心(說到底核心是一個(gè)?beanName->?beanDefinition?的?map) ??????ConfigurableListableBeanFactory?beanFactory?=?obtainFreshBeanFactory();??????//?設(shè)置?BeanFactory?的類加載器,添加幾個(gè)?BeanPostProcessor,手動(dòng)注冊(cè)幾個(gè)特殊的?bean ??????//?這塊待會(huì)會(huì)展開說 ??????prepareBeanFactory(beanFactory);??????try?{?????????//?【這里需要知道?BeanFactoryPostProcessor?這個(gè)知識(shí)點(diǎn),Bean?如果實(shí)現(xiàn)了此接口, ?????????//?那么在容器初始化以后,Spring?會(huì)負(fù)責(zé)調(diào)用里面的?postProcessBeanFactory?方法。】 ?????????//?這里是提供給子類的擴(kuò)展點(diǎn),到這里的時(shí)候,所有的?Bean?都加載、注冊(cè)完成了,但是都還沒有初始化 ?????????//?具體的子類可以在這步的時(shí)候添加一些特殊的?BeanFactoryPostProcessor?的實(shí)現(xiàn)類或做點(diǎn)什么事 ?????????postProcessBeanFactory(beanFactory);?????????//?調(diào)用?BeanFactoryPostProcessor?各個(gè)實(shí)現(xiàn)類的?postProcessBeanFactory(factory)?方法 ?????????invokeBeanFactoryPostProcessors(beanFactory);?????????//?注冊(cè)?BeanPostProcessor?的實(shí)現(xiàn)類,注意看和?BeanFactoryPostProcessor?的區(qū)別 ?????????//?此接口兩個(gè)方法:?postProcessBeforeInitialization?和?postProcessAfterInitialization ?????????//?兩個(gè)方法分別在?Bean?初始化之前和初始化之后得到執(zhí)行。注意,到這里?Bean?還沒初始化 ?????????registerBeanPostProcessors(beanFactory);?????????//?初始化當(dāng)前?ApplicationContext?的?MessageSource,國際化這里就不展開說了,不然沒完沒了了 ?????????initMessageSource();?????????//?初始化當(dāng)前?ApplicationContext?的事件廣播器,這里也不展開了 ?????????initApplicationEventMulticaster();?????????//?從方法名就可以知道,典型的模板方法(鉤子方法), ?????????//?具體的子類可以在這里初始化一些特殊的?Bean(在初始化?singleton?beans?之前) ?????????onRefresh();?????????//?注冊(cè)事件監(jiān)聽器,監(jiān)聽器需要實(shí)現(xiàn)?ApplicationListener?接口。這也不是我們的重點(diǎn),過 ?????????registerListeners();?????????//?重點(diǎn),重點(diǎn),重點(diǎn) ?????????//?初始化所有的?singleton?beans ?????????//(lazy-init?的除外) ?????????finishBeanFactoryInitialization(beanFactory);?????????//?最后,廣播事件,ApplicationContext?初始化完成 ?????????finishRefresh(); ??????}??????catch?(BeansException?ex)?{?????????if?(logger.isWarnEnabled())?{ ????????????logger.warn("Exception?encountered?during?context?initialization?-?"?+??????????????????"cancelling?refresh?attempt:?"?+?ex); ?????????}?????????//?Destroy?already?created?singletons?to?avoid?dangling?resources. ?????????//?銷毀已經(jīng)初始化的?singleton?的?Beans,以免有些?bean?會(huì)一直占用資源 ?????????destroyBeans();?????????//?Reset?'active'?flag. ?????????cancelRefresh(ex);?????????//?把異常往外拋 ?????????throw?ex; ??????}??????finally?{?????????//?Reset?common?introspection?caches?in?Spring's?core,?since?we ?????????//?might?not?ever?need?metadata?for?singleton?beans?anymore... ?????????resetCommonCaches(); ??????} ???} }
下面,我們開始一步步來肢解這個(gè) refresh() 方法。
這個(gè)比較簡單,直接看代碼中的幾個(gè)注釋即可。
protected?void?prepareRefresh()?{???//?記錄啟動(dòng)時(shí)間, ???//?將?active?屬性設(shè)置為?true,closed?屬性設(shè)置為?false,它們都是?AtomicBoolean?類型 ???this.startupDate?=?System.currentTimeMillis();???this.closed.set(false);???this.active.set(true);???if?(logger.isInfoEnabled())?{ ??????logger.info("Refreshing?"?+?this); ???}???//?Initialize?any?placeholder?property?sources?in?the?context?environment ???initPropertySources();???//?校驗(yàn)?xml?配置文件 ???getEnvironment().validateRequiredProperties();???this.earlyApplicationEvents?=?new?LinkedHashSet<ApplicationEvent>(); }
我們回到 refresh() 方法中的下一行 obtainFreshBeanFactory()。
注意,這個(gè)方法是全文最重要的部分之一,這里將會(huì)初始化 BeanFactory、加載 Bean、注冊(cè) Bean 等等。
當(dāng)然,這步結(jié)束后,Bean 并沒有完成初始化。這里指的是 Bean 實(shí)例并未在這一步生成。
// AbstractApplicationContext.java
protected?ConfigurableListableBeanFactory?obtainFreshBeanFactory()?{???//?關(guān)閉舊的?BeanFactory?(如果有),創(chuàng)建新的?BeanFactory,加載?Bean?定義、注冊(cè)?Bean?等等 ???refreshBeanFactory();???//?返回剛剛創(chuàng)建的?BeanFactory ???ConfigurableListableBeanFactory?beanFactory?=?getBeanFactory();???if?(logger.isDebugEnabled())?{ ??????logger.debug("Bean?factory?for?"?+?getDisplayName()?+?":?"?+?beanFactory); ???}???return?beanFactory; }
// AbstractRefreshableApplicationContext.java 120
@Overrideprotected?final?void?refreshBeanFactory()?throws?BeansException?{???//?如果?ApplicationContext?中已經(jīng)加載過?BeanFactory?了,銷毀所有?Bean,關(guān)閉?BeanFactory ???//?注意,應(yīng)用中?BeanFactory?本來就是可以多個(gè)的,這里可不是說應(yīng)用全局是否有?BeanFactory,而是當(dāng)前 ???//?ApplicationContext?是否有?BeanFactory ???if?(hasBeanFactory())?{ ??????destroyBeans(); ??????closeBeanFactory(); ???}???try?{??????//?初始化一個(gè)?DefaultListableBeanFactory,為什么用這個(gè),我們馬上說。 ??????DefaultListableBeanFactory?beanFactory?=?createBeanFactory();??????//?用于?BeanFactory?的序列化,我想不部分人應(yīng)該都用不到 ??????beanFactory.setSerializationId(getId());??????//?下面這兩個(gè)方法很重要,別跟丟了,具體細(xì)節(jié)之后說 ??????//?設(shè)置?BeanFactory?的兩個(gè)配置屬性:是否允許?Bean?覆蓋、是否允許循環(huán)引用 ??????customizeBeanFactory(beanFactory);??????//?加載?Bean?到?BeanFactory?中 ??????loadBeanDefinitions(beanFactory);??????synchronized?(this.beanFactoryMonitor)?{?????????this.beanFactory?=?beanFactory; ??????} ???}???catch?(IOException?ex)?{??????throw?new?ApplicationContextException("I/O?error?parsing?bean?definition?source?for?"?+?getDisplayName(),?ex); ???} }
看到這里的時(shí)候,我覺得讀者就應(yīng)該站在高處看 ApplicationContext 了,ApplicationContext 繼承自 BeanFactory,但是它不應(yīng)該被理解為 BeanFactory 的實(shí)現(xiàn)類,而是說其內(nèi)部持有一個(gè)實(shí)例化的 BeanFactory(DefaultListableBeanFactory)。以后所有的 BeanFactory 相關(guān)的操作其實(shí)是委托給這個(gè)實(shí)例來處理的。
我們說說為什么選擇實(shí)例化?DefaultListableBeanFactory??前面我們說了有個(gè)很重要的接口 ConfigurableListableBeanFactory,它實(shí)現(xiàn)了 BeanFactory 下面一層的所有三個(gè)接口,我把之前的繼承圖再拿過來大家再仔細(xì)看一下:
我們可以看到 ConfigurableListableBeanFactory 只有一個(gè)實(shí)現(xiàn)類 DefaultListableBeanFactory,而且實(shí)現(xiàn)類 DefaultListableBeanFactory 還通過實(shí)現(xiàn)右邊的 AbstractAutowireCapableBeanFactory 通吃了右路。所以結(jié)論就是,最底下這個(gè)家伙 DefaultListableBeanFactory 基本上是最牛的 BeanFactory 了,這也是為什么這邊會(huì)使用這個(gè)類來實(shí)例化的原因。
如果你想要在程序運(yùn)行的時(shí)候動(dòng)態(tài)往 Spring IOC 容器注冊(cè)新的 bean,就會(huì)使用到這個(gè)類。那我們?cè)趺丛谶\(yùn)行時(shí)獲得這個(gè)實(shí)例呢?
之前我們說過 ApplicationContext 接口能獲取到 AutowireCapableBeanFactory,就是最右上角那個(gè),然后它向下轉(zhuǎn)型就能得到 DefaultListableBeanFactory 了。
在繼續(xù)往下之前,我們需要先了解 BeanDefinition。我們說 BeanFactory 是 Bean 容器,那么 Bean 又是什么呢?
這里的 BeanDefinition 就是我們所說的 Spring 的 Bean,我們自己定義的各個(gè) Bean 其實(shí)會(huì)轉(zhuǎn)換成一個(gè)個(gè) BeanDefinition 存在于 Spring 的 BeanFactory 中。
所以,如果有人問你 Bean 是什么的時(shí)候,你要知道 Bean 在代碼層面上可以認(rèn)為是 BeanDefinition 的實(shí)例。
BeanDefinition 中保存了我們的 Bean 信息,比如這個(gè) Bean 指向的是哪個(gè)類、是否是單例的、是否懶加載、這個(gè) Bean 依賴了哪些 Bean 等等。
我們來看下 BeanDefinition 的接口定義:
public?interface?BeanDefinition?extends?AttributeAccessor,?BeanMetadataElement?{???//?我們可以看到,默認(rèn)只提供?sington?和?prototype?兩種, ???//?很多讀者可能知道還有?request,?session,?globalSession,?application,?websocket?這幾種, ???//?不過,它們屬于基于?web?的擴(kuò)展。 ???String?SCOPE_SINGLETON?=?ConfigurableBeanFactory.SCOPE_SINGLETON; ???String?SCOPE_PROTOTYPE?=?ConfigurableBeanFactory.SCOPE_PROTOTYPE;???//?比較不重要,直接跳過吧 ???int?ROLE_APPLICATION?=?0;???int?ROLE_SUPPORT?=?1;???int?ROLE_INFRASTRUCTURE?=?2;???//?設(shè)置父?Bean,這里涉及到?bean?繼承,不是?java?繼承。請(qǐng)參見附錄的詳細(xì)介紹 ???//?一句話就是:繼承父?Bean?的配置信息而已 ???void?setParentName(String?parentName);???//?獲取父?Bean ???String?getParentName();???//?設(shè)置?Bean?的類名稱,將來是要通過反射來生成實(shí)例的 ???void?setBeanClassName(String?beanClassName);???//?獲取?Bean?的類名稱 ???String?getBeanClassName();???//?設(shè)置?bean?的?scope ???void?setScope(String?scope);???String?getScope();???//?設(shè)置是否懶加載 ???void?setLazyInit(boolean?lazyInit);???boolean?isLazyInit();???//?設(shè)置該?Bean?依賴的所有的?Bean,注意,這里的依賴不是指屬性依賴(如?@Autowire?標(biāo)記的), ???//?是?depends-on=""?屬性設(shè)置的值。 ???void?setDependsOn(String...?dependsOn);???//?返回該?Bean?的所有依賴 ???String[]?getDependsOn();???//?設(shè)置該?Bean?是否可以注入到其他?Bean?中,只對(duì)根據(jù)類型注入有效, ???//?如果根據(jù)名稱注入,即使這邊設(shè)置了?false,也是可以的 ???void?setAutowireCandidate(boolean?autowireCandidate);???//?該?Bean?是否可以注入到其他?Bean?中 ???boolean?isAutowireCandidate();???//?主要的。同一接口的多個(gè)實(shí)現(xiàn),如果不指定名字的話,Spring?會(huì)優(yōu)先選擇設(shè)置?primary?為?true?的?bean ???void?setPrimary(boolean?primary);???//?是否是?primary?的 ???boolean?isPrimary();???//?如果該?Bean?采用工廠方法生成,指定工廠名稱。對(duì)工廠不熟悉的讀者,請(qǐng)參加附錄 ???//?一句話就是:有些實(shí)例不是用反射生成的,而是用工廠模式生成的 ???void?setFactoryBeanName(String?factoryBeanName);???//?獲取工廠名稱 ???String?getFactoryBeanName();???//?指定工廠類中的?工廠方法名稱 ???void?setFactoryMethodName(String?factoryMethodName);???//?獲取工廠類中的?工廠方法名稱 ???String?getFactoryMethodName();???//?構(gòu)造器參數(shù) ???ConstructorArgumentValues?getConstructorArgumentValues();???//?Bean?中的屬性值,后面給?bean?注入屬性值的時(shí)候會(huì)說到 ???MutablePropertyValues?getPropertyValues();???//?是否?singleton ???boolean?isSingleton();???//?是否?prototype ???boolean?isPrototype();???//?如果這個(gè)?Bean?是被設(shè)置為?abstract,那么不能實(shí)例化, ???//?常用于作為?父bean?用于繼承,其實(shí)也很少用...... ???boolean?isAbstract();???int?getRole();???String?getDescription();???String?getResourceDescription();???BeanDefinition?getOriginatingBeanDefinition(); }
這個(gè) BeanDefinition 其實(shí)已經(jīng)包含很多的信息了,暫時(shí)不清楚所有的方法對(duì)應(yīng)什么東西沒關(guān)系,希望看完本文后讀者可以徹底搞清楚里面的所有東西。
這里接口雖然那么多,但是沒有類似 getInstance() 這種方法來獲取我們定義的類的實(shí)例,真正的我們定義的類生成的實(shí)例到哪里去了呢?別著急,這個(gè)要很后面才能講到。
有了 BeanDefinition 的概念以后,我們?cè)偻驴?refreshBeanFactory() 方法中的剩余部分:
customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory);
雖然只有兩個(gè)方法,但路還很長啊。。。
customizeBeanFactory(beanFactory) 比較簡單,就是配置是否允許 BeanDefinition 覆蓋、是否允許循環(huán)引用。
protected?void?customizeBeanFactory(DefaultListableBeanFactory?beanFactory)?{???if?(this.allowBeanDefinitionOverriding?!=?null)?{??????//?是否允許?Bean?定義覆蓋 ??????beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); ???}???if?(this.allowCircularReferences?!=?null)?{??????//?是否允許?Bean?間的循環(huán)依賴 ??????beanFactory.setAllowCircularReferences(this.allowCircularReferences); ???} }
BeanDefinition 的覆蓋問題可能會(huì)有開發(fā)者碰到這個(gè)坑,就是在配置文件中定義 bean 時(shí)使用了相同的 id 或 name,默認(rèn)情況下,allowBeanDefinitionOverriding 屬性為 null,如果在同一配置文件中重復(fù)了,會(huì)拋錯(cuò),但是如果不是同一配置文件中,會(huì)發(fā)生覆蓋。
循環(huán)引用也很好理解:A 依賴 B,而 B 依賴 A?;?A 依賴 B,B 依賴 C,而 C 依賴 A。
默認(rèn)情況下,Spring 允許循環(huán)依賴,當(dāng)然如果你在 A 的構(gòu)造方法中依賴 B,在 B 的構(gòu)造方法中依賴 A 是不行的。
至于這兩個(gè)屬性怎么配置?我在附錄中進(jìn)行了介紹,尤其對(duì)于覆蓋問題,很多人都希望禁止出現(xiàn) Bean 覆蓋,可是 Spring 默認(rèn)是不同文件的時(shí)候可以覆蓋的。
之后的源碼中還會(huì)出現(xiàn)這兩個(gè)屬性,讀者有個(gè)印象就可以了。
接下來是最重要的 loadBeanDefinitions(beanFactory) 方法了,這個(gè)方法將根據(jù)配置,加載各個(gè) Bean,然后放到 BeanFactory 中。
讀取配置的操作在 XmlBeanDefinitionReader 中,其負(fù)責(zé)加載配置、解析。
// AbstractXmlApplicationContext.java 80
/**?我們可以看到,此方法將通過一個(gè)?XmlBeanDefinitionReader?實(shí)例來加載各個(gè)?Bean。*/@Overrideprotected?void?loadBeanDefinitions(DefaultListableBeanFactory?beanFactory)?throws?BeansException,?IOException?{???//?給這個(gè)?BeanFactory?實(shí)例化一個(gè)?XmlBeanDefinitionReader ???XmlBeanDefinitionReader?beanDefinitionReader?=?new?XmlBeanDefinitionReader(beanFactory);???//?Configure?the?bean?definition?reader?with?this?context's ???//?resource?loading?environment. ???beanDefinitionReader.setEnvironment(this.getEnvironment()); ???beanDefinitionReader.setResourceLoader(this); ???beanDefinitionReader.setEntityResolver(new?ResourceEntityResolver(this));???//?初始化?BeanDefinitionReader,其實(shí)這個(gè)是提供給子類覆寫的, ???//?我看了一下,沒有類覆寫這個(gè)方法,我們姑且當(dāng)做不重要吧 ???initBeanDefinitionReader(beanDefinitionReader);???//?重點(diǎn)來了,繼續(xù)往下 ???loadBeanDefinitions(beanDefinitionReader); }
現(xiàn)在還在這個(gè)類中,接下來用剛剛初始化的 Reader 開始來加載 xml 配置,這塊代碼讀者可以選擇性跳過,不是很重要。也就是說,下面這個(gè)代碼塊,讀者可以很輕松地略過。
// AbstractXmlApplicationContext.java 120
protected?void?loadBeanDefinitions(XmlBeanDefinitionReader?reader)?throws?BeansException,?IOException?{ ???Resource[]?configResources?=?getConfigResources();???if?(configResources?!=?null)?{??????//?往下看 ??????reader.loadBeanDefinitions(configResources); ???} ???String[]?configLocations?=?getConfigLocations();???if?(configLocations?!=?null)?{??????//?2 ??????reader.loadBeanDefinitions(configLocations); ???} }//?上面雖然有兩個(gè)分支,不過第二個(gè)分支很快通過解析路徑轉(zhuǎn)換為?Resource?以后也會(huì)進(jìn)到這里@Overridepublic?int?loadBeanDefinitions(Resource...?resources)?throws?BeanDefinitionStoreException?{ ???Assert.notNull(resources,?"Resource?array?must?not?be?null");???int?counter?=?0;???//?注意這里是個(gè)?for?循環(huán),也就是每個(gè)文件是一個(gè)?resource ???for?(Resource?resource?:?resources)?{??????//?繼續(xù)往下看 ??????counter?+=?loadBeanDefinitions(resource); ???}???//?最后返回?counter,表示總共加載了多少的?BeanDefinition ???return?counter; }//?XmlBeanDefinitionReader?303@Overridepublic?int?loadBeanDefinitions(Resource?resource)?throws?BeanDefinitionStoreException?{???return?loadBeanDefinitions(new?EncodedResource(resource)); }//?XmlBeanDefinitionReader?314public?int?loadBeanDefinitions(EncodedResource?encodedResource)?throws?BeanDefinitionStoreException?{ ???Assert.notNull(encodedResource,?"EncodedResource?must?not?be?null");???if?(logger.isInfoEnabled())?{ ??????logger.info("Loading?XML?bean?definitions?from?"?+?encodedResource.getResource()); ???}???//?用一個(gè)?ThreadLocal?來存放配置文件資源 ???Set<EncodedResource>?currentResources?=?this.resourcesCurrentlyBeingLoaded.get();???if?(currentResources?==?null)?{ ??????currentResources?=?new?HashSet<EncodedResource>(4);??????this.resourcesCurrentlyBeingLoaded.set(currentResources); ???}???if?(!currentResources.add(encodedResource))?{??????throw?new?BeanDefinitionStoreException(????????????"Detected?cyclic?loading?of?"?+?encodedResource?+?"?-?check?your?import?definitions!"); ???}???try?{ ??????InputStream?inputStream?=?encodedResource.getResource().getInputStream();??????try?{ ?????????InputSource?inputSource?=?new?InputSource(inputStream);?????????if?(encodedResource.getEncoding()?!=?null)?{ ????????????inputSource.setEncoding(encodedResource.getEncoding()); ?????????}?????????//?核心部分是這里,往下面看 ?????????return?doLoadBeanDefinitions(inputSource,?encodedResource.getResource()); ??????}??????finally?{ ?????????inputStream.close(); ??????} ???}???catch?(IOException?ex)?{??????throw?new?BeanDefinitionStoreException(????????????"IOException?parsing?XML?document?from?"?+?encodedResource.getResource(),?ex); ???}???finally?{ ??????currentResources.remove(encodedResource);??????if?(currentResources.isEmpty())?{?????????this.resourcesCurrentlyBeingLoaded.remove(); ??????} ???} }//?還在這個(gè)文件中,第?388?行protected?int?doLoadBeanDefinitions(InputSource?inputSource,?Resource?resource) ??????throws?BeanDefinitionStoreException?{???try?{??????//?這里就不看了,將?xml?文件轉(zhuǎn)換為?Document?對(duì)象 ??????Document?doc?=?doLoadDocument(inputSource,?resource);??????//?繼續(xù) ??????return?registerBeanDefinitions(doc,?resource); ???}???catch?(... }//?還在這個(gè)文件中,第?505?行//?返回值:返回從當(dāng)前配置文件加載了多少數(shù)量的?Beanpublic?int?registerBeanDefinitions(Document?doc,?Resource?resource)?throws?BeanDefinitionStoreException?{ ???BeanDefinitionDocumentReader?documentReader?=?createBeanDefinitionDocumentReader();???int?countBefore?=?getRegistry().getBeanDefinitionCount();???//?這里 ???documentReader.registerBeanDefinitions(doc,?createReaderContext(resource));???return?getRegistry().getBeanDefinitionCount()?-?countBefore; }//?DefaultBeanDefinitionDocumentReader?90@Overridepublic?void?registerBeanDefinitions(Document?doc,?XmlReaderContext?readerContext)?{???this.readerContext?=?readerContext; ???logger.debug("Loading?bean?definitions"); ???Element?root?=?doc.getDocumentElement();???//?從?xml?根節(jié)點(diǎn)開始解析文件 ???doRegisterBeanDefinitions(root); }
經(jīng)過漫長的鏈路,一個(gè)配置文件終于轉(zhuǎn)換為一顆 DOM 樹了,注意,這里指的是其中一個(gè)配置文件,不是所有的,讀者可以看到上面有個(gè) for 循環(huán)的。下面開始從根節(jié)點(diǎn)開始解析:
doRegisterBeanDefinitions:
//?DefaultBeanDefinitionDocumentReader?116protected?void?doRegisterBeanDefinitions(Element?root)?{???//?我們看名字就知道,BeanDefinitionParserDelegate?必定是一個(gè)重要的類,它負(fù)責(zé)解析?Bean?定義, ???//?這里為什么要定義一個(gè)?parent??看到后面就知道了,是遞歸問題, ???//?因?yàn)?<beans?/>?內(nèi)部是可以定義?<beans?/>?的,所以這個(gè)方法的?root?其實(shí)不一定就是?xml?的根節(jié)點(diǎn),也可以是嵌套在里面的?<beans?/>?節(jié)點(diǎn),從源碼分析的角度,我們當(dāng)做根節(jié)點(diǎn)就好了 ???BeanDefinitionParserDelegate?parent?=?this.delegate;???this.delegate?=?createDelegate(getReaderContext(),?root,?parent);???if?(this.delegate.isDefaultNamespace(root))?{??????//?這塊說的是根節(jié)點(diǎn)?<beans?...?profile="dev"?/>?中的?profile?是否是當(dāng)前環(huán)境需要的, ??????//?如果當(dāng)前環(huán)境配置的?profile?不包含此?profile,那就直接?return?了,不對(duì)此?<beans?/>?解析 ??????//?不熟悉?profile?為何物,不熟悉怎么配置?profile?讀者的請(qǐng)移步附錄區(qū) ??????String?profileSpec?=?root.getAttribute(PROFILE_ATTRIBUTE);??????if?(StringUtils.hasText(profileSpec))?{ ?????????String[]?specifiedProfiles?=?StringUtils.tokenizeToStringArray( ???????????????profileSpec,?BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);?????????if?(!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles))?{????????????if?(logger.isInfoEnabled())?{ ???????????????logger.info("Skipped?XML?bean?definition?file?due?to?specified?profiles?["?+?profileSpec?+?????????????????????"]?not?matching:?"?+?getReaderContext().getResource()); ????????????}????????????return; ?????????} ??????} ???} ???preProcessXml(root);?//?鉤子 ???//?往下看 ???parseBeanDefinitions(root,?this.delegate); ???postProcessXml(root);?//?鉤子 ???this.delegate?=?parent; }
preProcessXml(root) 和 postProcessXml(root) 是給子類用的鉤子方法,鑒于沒有被使用到,也不是我們的重點(diǎn),我們直接跳過。
這里涉及到了 profile 的問題,對(duì)于不了解的讀者,我在附錄中對(duì) profile 做了簡單的解釋,讀者可以參考一下。
接下來,看核心解析方法 parseBeanDefinitions(root, this.delegate) :
//?default?namespace?涉及到的就四個(gè)標(biāo)簽?<import?/>、<alias?/>、<bean?/>?和?<beans?/>,//?其他的屬于?custom?的protected?void?parseBeanDefinitions(Element?root,?BeanDefinitionParserDelegate?delegate)?{???if?(delegate.isDefaultNamespace(root))?{ ??????NodeList?nl?=?root.getChildNodes();??????for?(int?i?=?0;?i?<?nl.getLength();?i++)?{ ?????????Node?node?=?nl.item(i);?????????if?(node?instanceof?Element)?{ ????????????Element?ele?=?(Element)?node;????????????if?(delegate.isDefaultNamespace(ele))?{???????????????//?解析?default?namespace?下面的幾個(gè)元素 ???????????????parseDefaultElement(ele,?delegate); ????????????}????????????else?{???????????????//?解析其他?namespace?的元素 ???????????????delegate.parseCustomElement(ele); ????????????} ?????????} ??????} ???}???else?{??????delegate.parseCustomElement(root); ???} }
從上面的代碼,我們可以看到,對(duì)于每個(gè)配置來說,分別進(jìn)入到 parseDefaultElement(ele, delegate); 和 delegate.parseCustomElement(ele); 這兩個(gè)分支了。
parseDefaultElement(ele, delegate) 代表解析的節(jié)點(diǎn)是?<import />
、<alias />
、<bean />
、<beans />
?這幾個(gè)。
這里的四個(gè)標(biāo)簽之所以是 default 的,是因?yàn)樗鼈兪翘幱谶@個(gè) namespace 下定義的:
http://www.springframework.org/schema/beans又到初學(xué)者科普時(shí)間,不熟悉 namespace 的讀者請(qǐng)看下面貼出來的 xml,這里的第二行?xmlns?就是咯。
<beans?xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ???????xmlns="http://www.springframework.org/schema/beans" ???????xsi:schemaLocation=" ????????????http://www.springframework.org/schema/beans ??????????http://www.springframework.org/schema/beans/spring-beans.xsd" ???????default-autowire="byName">而對(duì)于其他的標(biāo)簽,將進(jìn)入到 delegate.parseCustomElement(element) 這個(gè)分支。如我們經(jīng)常會(huì)使用到的?
<mvc />
、<task />
、<context />
、<aop />
等。這些屬于擴(kuò)展,如果需要使用上面這些 ”非 default“ 標(biāo)簽,那么上面的 xml 頭部的地方也要引入相應(yīng)的 namespace 和 .xsd 文件的路徑,如下所示。同時(shí)代碼中需要提供相應(yīng)的 parser 來解析,如 MvcNamespaceHandler、TaskNamespaceHandler、ContextNamespaceHandler、AopNamespaceHandler 等。
假如讀者想分析?
<context:property-placeholder location="classpath:xx.properties" />
?的實(shí)現(xiàn)原理,就應(yīng)該到 ContextNamespaceHandler 中找答案。<beans?xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ??????xmlns="http://www.springframework.org/schema/beans" ??????xmlns:context="http://www.springframework.org/schema/context" ??????xmlns:mvc="http://www.springframework.org/schema/mvc" ??????xsi:schemaLocation=" ???????????http://www.springframework.org/schema/beans? ???????????http://www.springframework.org/schema/beans/spring-beans.xsd ???????????http://www.springframework.org/schema/context ???????????http://www.springframework.org/schema/context/spring-context.xsd ???????????http://www.springframework.org/schema/mvc??? ???????????http://www.springframework.org/schema/mvc/spring-mvc.xsd?? ???????" ??????default-autowire="byName">
回過神來,看看處理 default 標(biāo)簽的方法:
private?void?parseDefaultElement(Element?ele,?BeanDefinitionParserDelegate?delegate)?{???if?(delegate.nodeNameEquals(ele,?IMPORT_ELEMENT))?{??????//?處理?<import?/>?標(biāo)簽 ??????importBeanDefinitionResource(ele); ???}???else?if?(delegate.nodeNameEquals(ele,?ALIAS_ELEMENT))?{??????//?處理?<alias?/>?標(biāo)簽定義 ??????//?<alias?name="fromName"?alias="toName"/> ??????processAliasRegistration(ele); ???}???else?if?(delegate.nodeNameEquals(ele,?BEAN_ELEMENT))?{??????//?處理?<bean?/>?標(biāo)簽定義,這也算是我們的重點(diǎn)吧 ??????processBeanDefinition(ele,?delegate); ???}???else?if?(delegate.nodeNameEquals(ele,?NESTED_BEANS_ELEMENT))?{??????//?如果碰到的是嵌套的?<beans?/>?標(biāo)簽,需要遞歸 ??????doRegisterBeanDefinitions(ele); ???} }
如果每個(gè)標(biāo)簽都說,那我不吐血,你們都要吐血了。我們挑我們的重點(diǎn)?<bean />
?標(biāo)簽出來說。
processBeanDefinition 解析 bean 標(biāo)簽
下面是 processBeanDefinition 解析?<bean />
?標(biāo)簽:
// DefaultBeanDefinitionDocumentReader 298
protected?void?processBeanDefinition(Element?ele,?BeanDefinitionParserDelegate?delegate)?{???//?將?<bean?/>?節(jié)點(diǎn)中的信息提取出來,然后封裝到一個(gè)?BeanDefinitionHolder?中,細(xì)節(jié)往下看 ???BeanDefinitionHolder?bdHolder?=?delegate.parseBeanDefinitionElement(ele);???//?下面的幾行先不要看,跳過先,跳過先,跳過先,后面會(huì)繼續(xù)說的 ???if?(bdHolder?!=?null)?{ ??????bdHolder?=?delegate.decorateBeanDefinitionIfRequired(ele,?bdHolder);??????try?{?????????//?Register?the?final?decorated?instance. ?????????BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,?getReaderContext().getRegistry()); ??????}??????catch?(BeanDefinitionStoreException?ex)?{ ?????????getReaderContext().error("Failed?to?register?bean?definition?with?name?'"?+ ???????????????bdHolder.getBeanName()?+?"'",?ele,?ex); ??????}??????//?Send?registration?event. ??????getReaderContext().fireComponentRegistered(new?BeanComponentDefinition(bdHolder)); ???} }
繼續(xù)往下看怎么解析之前,我們先看下?<bean />
?標(biāo)簽中可以定義哪些屬性:
Property | ? |
---|---|
class | 類的全限定名 |
name | 可指定 id、name(用逗號(hào)、分號(hào)、空格分隔) |
scope | 作用域 |
constructor arguments | 指定構(gòu)造參數(shù) |
properties | 設(shè)置屬性的值 |
autowiring mode | no(默認(rèn)值)、byName、byType、 constructor |
lazy-initialization mode | 是否懶加載(如果被非懶加載的bean依賴了那么其實(shí)也就不能懶加載了) |
initialization method | bean 屬性設(shè)置完成后,會(huì)調(diào)用這個(gè)方法 |
destruction method | bean 銷毀后的回調(diào)方法 |
上面表格中的內(nèi)容我想大家都非常熟悉吧,如果不熟悉,那就是你不夠了解 Spring 的配置了。
簡單地說就是像下面這樣子:
<bean?id="exampleBean"?name="name1,?name2,?name3"?class="com.javadoop.ExampleBean" ??????scope="singleton"?lazy-init="true"?init-method="init"?destroy-method="cleanup"> ????<!--?可以用下面三種形式指定構(gòu)造參數(shù)?--> ????<constructor-arg?type="int"?value="7500000"/> ????<constructor-arg?name="years"?value="7500000"/> ????<constructor-arg?index="0"?value="7500000"/> ????<!--?property?的幾種情況?--> ????<property?name="beanOne"> ????????<ref?bean="anotherExampleBean"/> ????</property> ????<property?name="beanTwo"?ref="yetAnotherBean"/> ????<property?name="integerProperty"?value="1"/></bean>
當(dāng)然,除了上面舉例出來的這些,還有 factory-bean、factory-method、<lockup-method />
、<replaced-method />
、<meta />
、<qualifier />
?這幾個(gè),大家是不是熟悉呢?自己檢驗(yàn)一下自己對(duì) Spring 中 bean 的了解程度。
有了以上這些知識(shí)以后,我們?cè)倮^續(xù)往里看怎么解析 bean 元素,是怎么轉(zhuǎn)換到 BeanDefinitionHolder 的。
// BeanDefinitionParserDelegate 428
public?BeanDefinitionHolder?parseBeanDefinitionElement(Element?ele)?{????return?parseBeanDefinitionElement(ele,?null); } public?BeanDefinitionHolder?parseBeanDefinitionElement(Element?ele,?BeanDefinition?containingBean)?{???String?id?=?ele.getAttribute(ID_ATTRIBUTE);???String?nameAttr?=?ele.getAttribute(NAME_ATTRIBUTE); ???List<String>?aliases?=?new?ArrayList<String>();???//?將?name?屬性的定義按照?“逗號(hào)、分號(hào)、空格”?切分,形成一個(gè)?別名列表數(shù)組, ???//?當(dāng)然,如果你不定義?name?屬性的話,就是空的了 ???//?我在附錄中簡單介紹了一下?id?和?name?的配置,大家可以看一眼,有個(gè)20秒就可以了 ???if?(StringUtils.hasLength(nameAttr))?{??????String[]?nameArr?=?StringUtils.tokenizeToStringArray(nameAttr,?MULTI_VALUE_ATTRIBUTE_DELIMITERS); ??????aliases.addAll(Arrays.asList(nameArr)); ???}???String?beanName?=?id;???//?如果沒有指定id,?那么用別名列表的第一個(gè)名字作為beanName ???if?(!StringUtils.hasText(beanName)?&&?!aliases.isEmpty())?{ ??????beanName?=?aliases.remove(0);??????if?(logger.isDebugEnabled())?{ ?????????logger.debug("No?XML?'id'?specified?-?using?'"?+?beanName?+???????????????"'?as?bean?name?and?"?+?aliases?+?"?as?aliases"); ??????} ???}???if?(containingBean?==?null)?{ ??????checkNameUniqueness(beanName,?aliases,?ele); ???}???//?根據(jù)?<bean?...>...</bean>?中的配置創(chuàng)建?BeanDefinition,然后把配置中的信息都設(shè)置到實(shí)例中, ???//?細(xì)節(jié)后面細(xì)說,先知道下面這行結(jié)束后,一個(gè)?BeanDefinition?實(shí)例就出來了。 ???AbstractBeanDefinition?beanDefinition?=?parseBeanDefinitionElement(ele,?beanName,?containingBean);???//?到這里,整個(gè)?<bean?/>?標(biāo)簽就算解析結(jié)束了,一個(gè)?BeanDefinition?就形成了。 ???if?(beanDefinition?!=?null)?{??????//?如果都沒有設(shè)置?id?和?name,那么此時(shí)的?beanName?就會(huì)為?null,進(jìn)入下面這塊代碼產(chǎn)生 ??????//?如果讀者不感興趣的話,我覺得不需要關(guān)心這塊代碼,對(duì)本文源碼分析來說,這些東西不重要 ??????if?(!StringUtils.hasText(beanName))?{?????????try?{????????????if?(containingBean?!=?null)?{//?按照我們的思路,這里?containingBean?是?null?的 ???????????????beanName?=?BeanDefinitionReaderUtils.generateBeanName( ?????????????????????beanDefinition,?this.readerContext.getRegistry(),?true); ????????????}????????????else?{???????????????//?如果我們不定義?id?和?name,那么我們引言里的那個(gè)例子: ???????????????//???1.?beanName?為:com.javadoop.example.MessageServiceImpl#0 ???????????????//???2.?beanClassName?為:com.javadoop.example.MessageServiceImpl ???????????????beanName?=?this.readerContext.generateBeanName(beanDefinition);???????????????String?beanClassName?=?beanDefinition.getBeanClassName();???????????????if?(beanClassName?!=?null?&& ?????????????????????beanName.startsWith(beanClassName)?&&?beanName.length()?>?beanClassName.length()?&& ?????????????????????!this.readerContext.getRegistry().isBeanNameInUse(beanClassName))?{??????????????????//?把?beanClassName?設(shè)置為?Bean?的別名 ??????????????????aliases.add(beanClassName); ???????????????} ????????????}????????????if?(logger.isDebugEnabled())?{ ???????????????logger.debug("Neither?XML?'id'?nor?'name'?specified?-?"?+?????????????????????"using?generated?bean?name?["?+?beanName?+?"]"); ????????????} ?????????}?????????catch?(Exception?ex)?{ ????????????error(ex.getMessage(),?ele);????????????return?null; ?????????} ??????}??????String[]?aliasesArray?=?StringUtils.toStringArray(aliases);??????//?返回?BeanDefinitionHolder ??????return?new?BeanDefinitionHolder(beanDefinition,?beanName,?aliasesArray); ???}???return?null; }
然后,我們?cè)倏纯丛趺锤鶕?jù)配置創(chuàng)建 BeanDefinition 實(shí)例的:
public?AbstractBeanDefinition?parseBeanDefinitionElement( ??????Element?ele,?String?beanName,?BeanDefinition?containingBean)?{???this.parseState.push(new?BeanEntry(beanName));???String?className?=?null;???if?(ele.hasAttribute(CLASS_ATTRIBUTE))?{ ??????className?=?ele.getAttribute(CLASS_ATTRIBUTE).trim(); ???}???try?{??????String?parent?=?null;??????if?(ele.hasAttribute(PARENT_ATTRIBUTE))?{ ?????????parent?=?ele.getAttribute(PARENT_ATTRIBUTE); ??????}??????//?創(chuàng)建?BeanDefinition,然后設(shè)置類信息而已,很簡單,就不貼代碼了 ??????AbstractBeanDefinition?bd?=?createBeanDefinition(className,?parent);??????//?設(shè)置?BeanDefinition?的一堆屬性,這些屬性定義在?AbstractBeanDefinition?中 ??????parseBeanDefinitionAttributes(ele,?beanName,?containingBean,?bd); ??????bd.setDescription(DomUtils.getChildElementValueByTagName(ele,?DESCRIPTION_ELEMENT));??????/** ???????*?下面的一堆是解析?<bean>......</bean>?內(nèi)部的子元素, ???????*?解析出來以后的信息都放到?bd?的屬性中 ???????*/ ??????//?解析?<meta?/> ??????parseMetaElements(ele,?bd);??????//?解析?<lookup-method?/> ??????parseLookupOverrideSubElements(ele,?bd.getMethodOverrides());??????//?解析?<replaced-method?/> ??????parseReplacedMethodSubElements(ele,?bd.getMethodOverrides());????//?解析?<constructor-arg?/> ??????parseConstructorArgElements(ele,?bd);??????//?解析?<property?/> ??????parsePropertyElements(ele,?bd);??????//?解析?<qualifier?/> ??????parseQualifierElements(ele,?bd); ??????bd.setResource(this.readerContext.getResource()); ??????bd.setSource(extractSource(ele));??????return?bd; ???}???catch?(ClassNotFoundException?ex)?{ ??????error("Bean?class?["?+?className?+?"]?not?found",?ele,?ex); ???}???catch?(NoClassDefFoundError?err)?{ ??????error("Class?that?bean?class?["?+?className?+?"]?depends?on?not?found",?ele,?err); ???}???catch?(Throwable?ex)?{ ??????error("Unexpected?failure?during?bean?definition?parsing",?ele,?ex); ???}???finally?{??????this.parseState.pop(); ???}???return?null; }
到這里,我們已經(jīng)完成了根據(jù)?<bean />
?配置創(chuàng)建了一個(gè) BeanDefinitionHolder 實(shí)例。注意,是一個(gè)。
我們回到解析?<bean />
?的入口方法:
protected?void?processBeanDefinition(Element?ele,?BeanDefinitionParserDelegate?delegate)?{???//?將?<bean?/>?節(jié)點(diǎn)轉(zhuǎn)換為?BeanDefinitionHolder,就是上面說的一堆 ???BeanDefinitionHolder?bdHolder?=?delegate.parseBeanDefinitionElement(ele);???if?(bdHolder?!=?null)?{??????//?如果有自定義屬性的話,進(jìn)行相應(yīng)的解析,先忽略 ??????bdHolder?=?delegate.decorateBeanDefinitionIfRequired(ele,?bdHolder);??????try?{?????????//?我們把這步叫做?注冊(cè)Bean?吧 ?????????BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,?getReaderContext().getRegistry()); ??????}??????catch?(BeanDefinitionStoreException?ex)?{ ?????????getReaderContext().error("Failed?to?register?bean?definition?with?name?'"?+ ???????????????bdHolder.getBeanName()?+?"'",?ele,?ex); ??????}??????//?注冊(cè)完成后,發(fā)送事件,本文不展開說這個(gè) ??????getReaderContext().fireComponentRegistered(new?BeanComponentDefinition(bdHolder)); ???} }
大家再仔細(xì)看一下這塊吧,我們后面就不回來說這個(gè)了。這里已經(jīng)根據(jù)一個(gè)?<bean />
?標(biāo)簽產(chǎn)生了一個(gè) BeanDefinitionHolder 的實(shí)例,這個(gè)實(shí)例里面也就是一個(gè) BeanDefinition 的實(shí)例和它的 beanName、aliases 這三個(gè)信息,注意,我們的關(guān)注點(diǎn)始終在 BeanDefinition 上:
public?class?BeanDefinitionHolder?implements?BeanMetadataElement?{??private?final?BeanDefinition?beanDefinition;??private?final?String?beanName;??private?final?String[]?aliases; ...
然后我們準(zhǔn)備注冊(cè)這個(gè) BeanDefinition,最后,把這個(gè)注冊(cè)事件發(fā)送出去。
下面,我們開始說說注冊(cè) Bean 吧。
注冊(cè) Bean
// BeanDefinitionReaderUtils 143
public?static?void?registerBeanDefinition( ??????BeanDefinitionHolder?definitionHolder,?BeanDefinitionRegistry?registry) ??????throws?BeanDefinitionStoreException?{ ???String?beanName?=?definitionHolder.getBeanName();???//?注冊(cè)這個(gè)?Bean ???registry.registerBeanDefinition(beanName,?definitionHolder.getBeanDefinition());???//?如果還有別名的話,也要根據(jù)別名全部注冊(cè)一遍,不然根據(jù)別名就會(huì)找不到?Bean?了 ???String[]?aliases?=?definitionHolder.getAliases();???if?(aliases?!=?null)?{??????for?(String?alias?:?aliases)?{?????????//?alias?->?beanName?保存它們的別名信息,這個(gè)很簡單,用一個(gè)?map?保存一下就可以了, ?????????//?獲取的時(shí)候,會(huì)先將?alias?轉(zhuǎn)換為?beanName,然后再查找 ?????????registry.registerAlias(beanName,?alias); ??????} ???} }
別名注冊(cè)的放一邊,畢竟它很簡單,我們看看怎么注冊(cè) Bean。
// DefaultListableBeanFactory 793
@Overridepublic?void?registerBeanDefinition(String?beanName,?BeanDefinition?beanDefinition) ??????throws?BeanDefinitionStoreException?{ ???Assert.hasText(beanName,?"Bean?name?must?not?be?empty"); ???Assert.notNull(beanDefinition,?"BeanDefinition?must?not?be?null");???if?(beanDefinition?instanceof?AbstractBeanDefinition)?{??????try?{ ?????????((AbstractBeanDefinition)?beanDefinition).validate(); ??????}??????catch?(BeanDefinitionValidationException?ex)?{?????????throw?new?BeanDefinitionStoreException(...); ??????} ???}???//?old??還記得?“允許?bean?覆蓋”?這個(gè)配置嗎?allowBeanDefinitionOverriding ???BeanDefinition?oldBeanDefinition;???//?之后會(huì)看到,所有的?Bean?注冊(cè)后會(huì)放入這個(gè)?beanDefinitionMap?中 ???oldBeanDefinition?=?this.beanDefinitionMap.get(beanName);???//?處理重復(fù)名稱的?Bean?定義的情況 ???if?(oldBeanDefinition?!=?null)?{??????if?(!isAllowBeanDefinitionOverriding())?{?????????//?如果不允許覆蓋的話,拋異常 ?????????throw?new?BeanDefinitionStoreException(beanDefinition.getResourceDescription()... ??????}??????else?if?(oldBeanDefinition.getRole()?<?beanDefinition.getRole())?{?????????//?log...用框架定義的?Bean?覆蓋用戶自定義的?Bean? ??????}??????else?if?(!beanDefinition.equals(oldBeanDefinition))?{?????????//?log...用新的?Bean?覆蓋舊的?Bean ??????}??????else?{?????????//?log...用同等的?Bean?覆蓋舊的?Bean,這里指的是?equals?方法返回?true?的?Bean ??????}??????//?覆蓋 ??????this.beanDefinitionMap.put(beanName,?beanDefinition); ???}???else?{??????//?判斷是否已經(jīng)有其他的?Bean?開始初始化了. ??????//?注意,"注冊(cè)Bean"?這個(gè)動(dòng)作結(jié)束,Bean?依然還沒有初始化,我們后面會(huì)有大篇幅說初始化過程, ??????//?在?Spring?容器啟動(dòng)的最后,會(huì)?預(yù)初始化?所有的?singleton?beans ??????if?(hasBeanCreationStarted())?{?????????//?Cannot?modify?startup-time?collection?elements?anymore?(for?stable?iteration) ?????????synchronized?(this.beanDefinitionMap)?{????????????this.beanDefinitionMap.put(beanName,?beanDefinition); ????????????List<String>?updatedDefinitions?=?new?ArrayList<String>(this.beanDefinitionNames.size()?+?1); ????????????updatedDefinitions.addAll(this.beanDefinitionNames); ????????????updatedDefinitions.add(beanName);????????????this.beanDefinitionNames?=?updatedDefinitions;????????????if?(this.manualSingletonNames.contains(beanName))?{ ???????????????Set<String>?updatedSingletons?=?new?LinkedHashSet<String>(this.manualSingletonNames); ???????????????updatedSingletons.remove(beanName);???????????????this.manualSingletonNames?=?updatedSingletons; ????????????} ?????????} ??????}??????else?{?????????//?最正常的應(yīng)該是進(jìn)到這個(gè)分支。 ?????????//?將?BeanDefinition?放到這個(gè)?map?中,這個(gè)?map?保存了所有的?BeanDefinition ?????????this.beanDefinitionMap.put(beanName,?beanDefinition);?????????//?這是個(gè)?ArrayList,所以會(huì)按照?bean?配置的順序保存每一個(gè)注冊(cè)的?Bean?的名字 ?????????this.beanDefinitionNames.add(beanName);?????????//?這是個(gè)?LinkedHashSet,代表的是手動(dòng)注冊(cè)的?singleton?bean, ?????????//?注意這里是?remove?方法,到這里的?Bean?當(dāng)然不是手動(dòng)注冊(cè)的 ?????????//?手動(dòng)指的是通過調(diào)用以下方法注冊(cè)的?bean?: ?????????//?????registerSingleton(String?beanName,?Object?singletonObject) ?????????//?這不是重點(diǎn),解釋只是為了不讓大家疑惑。Spring?會(huì)在后面"手動(dòng)"注冊(cè)一些?Bean, ?????????//?如?"environment"、"systemProperties"?等?bean,我們自己也可以在運(yùn)行時(shí)注冊(cè)?Bean?到容器中的 ?????????this.manualSingletonNames.remove(beanName); ??????}??????//?這個(gè)不重要,在預(yù)初始化的時(shí)候會(huì)用到,不必管它。 ??????this.frozenBeanDefinitionNames?=?null; ???}???if?(oldBeanDefinition?!=?null?||?containsSingleton(beanName))?{ ??????resetBeanDefinition(beanName); ???} }
總結(jié)一下,到這里已經(jīng)初始化了 Bean 容器,<bean />
?配置也相應(yīng)的轉(zhuǎn)換為了一個(gè)個(gè) BeanDefinition,然后注冊(cè)了各個(gè) BeanDefinition 到注冊(cè)中心,并且發(fā)送了注冊(cè)事件。
到這里是一個(gè)分水嶺,前面的內(nèi)容都還算比較簡單,大家要清楚地知道前面都做了哪些事情。
說到這里,我們回到 refresh() 方法,我重新貼了一遍代碼,看看我們說到哪了。是的,我們才說完 obtainFreshBeanFactory() 方法。
考慮到篇幅,這里開始大幅縮減掉沒必要詳細(xì)介紹的部分,大家直接看下面的代碼中的注釋就好了。
@Overridepublic?void?refresh()?throws?BeansException,?IllegalStateException?{???//?來個(gè)鎖,不然?refresh()?還沒結(jié)束,你又來個(gè)啟動(dòng)或銷毀容器的操作,那不就亂套了嘛 ???synchronized?(this.startupShutdownMonitor)?{??????//?準(zhǔn)備工作,記錄下容器的啟動(dòng)時(shí)間、標(biāo)記“已啟動(dòng)”狀態(tài)、處理配置文件中的占位符 ??????prepareRefresh();??????//?這步比較關(guān)鍵,這步完成后,配置文件就會(huì)解析成一個(gè)個(gè)?Bean?定義,注冊(cè)到?BeanFactory?中, ??????//?當(dāng)然,這里說的?Bean?還沒有初始化,只是配置信息都提取出來了, ??????//?注冊(cè)也只是將這些信息都保存到了注冊(cè)中心(說到底核心是一個(gè)?beanName->?beanDefinition?的?map) ??????ConfigurableListableBeanFactory?beanFactory?=?obtainFreshBeanFactory();??????//?設(shè)置?BeanFactory?的類加載器,添加幾個(gè)?BeanPostProcessor,手動(dòng)注冊(cè)幾個(gè)特殊的?bean ??????//?這塊待會(huì)會(huì)展開說 ??????prepareBeanFactory(beanFactory);??????try?{?????????//?【這里需要知道?BeanFactoryPostProcessor?這個(gè)知識(shí)點(diǎn),Bean?如果實(shí)現(xiàn)了此接口, ?????????//?那么在容器初始化以后,Spring?會(huì)負(fù)責(zé)調(diào)用里面的?postProcessBeanFactory?方法?!? ?????????//?這里是提供給子類的擴(kuò)展點(diǎn),到這里的時(shí)候,所有的?Bean?都加載、注冊(cè)完成了,但是都還沒有初始化 ?????????//?具體的子類可以在這步的時(shí)候添加一些特殊的?BeanFactoryPostProcessor?的實(shí)現(xiàn)類或做點(diǎn)什么事 ?????????postProcessBeanFactory(beanFactory);?????????//?調(diào)用?BeanFactoryPostProcessor?各個(gè)實(shí)現(xiàn)類的?postProcessBeanFactory(factory)?回調(diào)方法 ?????????invokeBeanFactoryPostProcessors(beanFactory);?????????? ?????????//?注冊(cè)?BeanPostProcessor?的實(shí)現(xiàn)類,注意看和?BeanFactoryPostProcessor?的區(qū)別 ?????????//?此接口兩個(gè)方法:?postProcessBeforeInitialization?和?postProcessAfterInitialization ?????????//?兩個(gè)方法分別在?Bean?初始化之前和初始化之后得到執(zhí)行。這里僅僅是注冊(cè),之后會(huì)看到回調(diào)這兩方法的時(shí)機(jī) ?????????registerBeanPostProcessors(beanFactory);?????????//?初始化當(dāng)前?ApplicationContext?的?MessageSource,國際化這里就不展開說了,不然沒完沒了了 ?????????initMessageSource();?????????//?初始化當(dāng)前?ApplicationContext?的事件廣播器,這里也不展開了 ?????????initApplicationEventMulticaster();?????????//?從方法名就可以知道,典型的模板方法(鉤子方法),不展開說 ?????????//?具體的子類可以在這里初始化一些特殊的?Bean(在初始化?singleton?beans?之前) ?????????onRefresh();?????????//?注冊(cè)事件監(jiān)聽器,監(jiān)聽器需要實(shí)現(xiàn)?ApplicationListener?接口。這也不是我們的重點(diǎn),過 ?????????registerListeners();?????????//?重點(diǎn),重點(diǎn),重點(diǎn) ?????????//?初始化所有的?singleton?beans ?????????//(lazy-init?的除外) ?????????finishBeanFactoryInitialization(beanFactory);?????????//?最后,廣播事件,ApplicationContext?初始化完成,不展開 ?????????finishRefresh(); ??????}??????catch?(BeansException?ex)?{?????????if?(logger.isWarnEnabled())?{ ????????????logger.warn("Exception?encountered?during?context?initialization?-?"?+??????????????????"cancelling?refresh?attempt:?"?+?ex); ?????????}?????????//?Destroy?already?created?singletons?to?avoid?dangling?resources. ?????????//?銷毀已經(jīng)初始化的?singleton?的?Beans,以免有些?bean?會(huì)一直占用資源 ?????????destroyBeans();?????????//?Reset?'active'?flag. ?????????cancelRefresh(ex);?????????//?把異常往外拋 ?????????throw?ex; ??????}??????finally?{?????????//?Reset?common?introspection?caches?in?Spring's?core,?since?we ?????????//?might?not?ever?need?metadata?for?singleton?beans?anymore... ?????????resetCommonCaches(); ??????} ???} }
之前我們說過,Spring 把我們?cè)?xml 配置的 bean 都注冊(cè)以后,會(huì)"手動(dòng)"注冊(cè)一些特殊的 bean。
這里簡單介紹下 prepareBeanFactory(factory) 方法:
/** ?*?Configure?the?factory's?standard?context?characteristics, ?*?such?as?the?context's?ClassLoader?and?post-processors. ?*?@param?beanFactory?the?BeanFactory?to?configure ?*/protected?void?prepareBeanFactory(ConfigurableListableBeanFactory?beanFactory)?{???//?設(shè)置?BeanFactory?的類加載器,我們知道?BeanFactory?需要加載類,也就需要類加載器, ???//?這里設(shè)置為加載當(dāng)前?ApplicationContext?類的類加載器 ???beanFactory.setBeanClassLoader(getClassLoader());???//?設(shè)置?BeanExpressionResolver ???beanFactory.setBeanExpressionResolver(new?StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));???//? ???beanFactory.addPropertyEditorRegistrar(new?ResourceEditorRegistrar(this,?getEnvironment()));???//?添加一個(gè)?BeanPostProcessor,這個(gè)?processor?比較簡單: ???//?實(shí)現(xiàn)了?Aware?接口的?beans?在初始化的時(shí)候,這個(gè)?processor?負(fù)責(zé)回調(diào), ???//?這個(gè)我們很常用,如我們會(huì)為了獲取?ApplicationContext?而?implement?ApplicationContextAware ???//?注意:它不僅僅回調(diào)?ApplicationContextAware, ???//???還會(huì)負(fù)責(zé)回調(diào)?EnvironmentAware、ResourceLoaderAware?等,看下源碼就清楚了 ???beanFactory.addBeanPostProcessor(new?ApplicationContextAwareProcessor(this));???//?下面幾行的意思就是,如果某個(gè)?bean?依賴于以下幾個(gè)接口的實(shí)現(xiàn)類,在自動(dòng)裝配的時(shí)候忽略它們, ???//?Spring?會(huì)通過其他方式來處理這些依賴。 ???beanFactory.ignoreDependencyInterface(EnvironmentAware.class); ???beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); ???beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); ???beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); ???beanFactory.ignoreDependencyInterface(MessageSourceAware.class); ???beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);???/** ????*?下面幾行就是為特殊的幾個(gè)?bean?賦值,如果有?bean?依賴了以下幾個(gè),會(huì)注入這邊相應(yīng)的值, ????*?之前我們說過,"當(dāng)前?ApplicationContext?持有一個(gè)?BeanFactory",這里解釋了第一行 ????*?ApplicationContext?還繼承了?ResourceLoader、ApplicationEventPublisher、MessageSource ????*?所以對(duì)于這幾個(gè)依賴,可以賦值為?this,注意?this?是一個(gè)?ApplicationContext ????*?那這里怎么沒看到為?MessageSource?賦值呢?那是因?yàn)?MessageSource?被注冊(cè)成為了一個(gè)普通的?bean ????*/ ???beanFactory.registerResolvableDependency(BeanFactory.class,?beanFactory); ???beanFactory.registerResolvableDependency(ResourceLoader.class,?this); ???beanFactory.registerResolvableDependency(ApplicationEventPublisher.class,?this); ???beanFactory.registerResolvableDependency(ApplicationContext.class,?this);???//?這個(gè)?BeanPostProcessor?也很簡單,在?bean?實(shí)例化后,如果是?ApplicationListener?的子類, ???//?那么將其添加到?listener?列表中,可以理解成:注冊(cè)?事件監(jiān)聽器 ???beanFactory.addBeanPostProcessor(new?ApplicationListenerDetector(this));???//?這里涉及到特殊的?bean,名為:loadTimeWeaver,這不是我們的重點(diǎn),忽略它 ???//?tips:?ltw?是?AspectJ?的概念,指的是在運(yùn)行期進(jìn)行織入,這個(gè)和?Spring?AOP?不一樣, ???//????感興趣的讀者請(qǐng)參考我寫的關(guān)于?AspectJ?的另一篇文章?https://www.javadoop.com/post/aspectj ???if?(beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME))?{ ??????beanFactory.addBeanPostProcessor(new?LoadTimeWeaverAwareProcessor(beanFactory));??????//?Set?a?temporary?ClassLoader?for?type?matching. ??????beanFactory.setTempClassLoader(new?ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); ???}???/** ????*?從下面幾行代碼我們可以知道,Spring?往往很?"智能"?就是因?yàn)樗鼤?huì)幫我們默認(rèn)注冊(cè)一些有用的?bean, ????*?我們也可以選擇覆蓋 ????*/ ???//?如果沒有定義?"environment"?這個(gè)?bean,那么?Spring?會(huì)?"手動(dòng)"?注冊(cè)一個(gè) ???if?(!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME))?{ ??????beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME,?getEnvironment()); ???}???//?如果沒有定義?"systemProperties"?這個(gè)?bean,那么?Spring?會(huì)?"手動(dòng)"?注冊(cè)一個(gè) ???if?(!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME))?{ ??????beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME,?getEnvironment().getSystemProperties()); ???}???//?如果沒有定義?"systemEnvironment"?這個(gè)?bean,那么?Spring?會(huì)?"手動(dòng)"?注冊(cè)一個(gè) ???if?(!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME))?{ ??????beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME,?getEnvironment().getSystemEnvironment()); ???} }
在上面這塊代碼中,Spring 對(duì)一些特殊的 bean 進(jìn)行了處理,讀者如果暫時(shí)還不能消化它們也沒有關(guān)系,慢慢往下看。
我們的重點(diǎn)當(dāng)然是 finishBeanFactoryInitialization(beanFactory); 這個(gè)巨頭了,這里會(huì)負(fù)責(zé)初始化所有的 singleton beans。
注意,后面的描述中,我都會(huì)使用初始化或預(yù)初始化來代表這個(gè)階段,Spring 會(huì)在這個(gè)階段完成所有的 singleton beans 的實(shí)例化。
我們來總結(jié)一下,到目前為止,應(yīng)該說 BeanFactory 已經(jīng)創(chuàng)建完成,并且所有的實(shí)現(xiàn)了 BeanFactoryPostProcessor 接口的 Bean 都已經(jīng)初始化并且其中的 postProcessBeanFactory(factory) 方法已經(jīng)得到回調(diào)執(zhí)行了。而且 Spring 已經(jīng)“手動(dòng)”注冊(cè)了一些特殊的 Bean,如 ‘environment’、‘systemProperties’ 等。
剩下的就是初始化 singleton beans 了,我們知道它們是單例的,如果沒有設(shè)置懶加載,那么 Spring 會(huì)在接下來初始化所有的 singleton beans。
// AbstractApplicationContext.java 834
//?初始化剩余的?singleton?beansprotected?void?finishBeanFactoryInitialization(ConfigurableListableBeanFactory?beanFactory)?{???//?首先,初始化名字為?conversionService?的?Bean。本著送佛送到西的精神,我在附錄中簡單介紹了一下?ConversionService,因?yàn)檫@實(shí)在太實(shí)用了 ???//?什么,看代碼這里沒有初始化?Bean???! ???//?注意了,初始化的動(dòng)作包裝在?beanFactory.getBean(...)?中,這里先不說細(xì)節(jié),先往下看吧 ???if?(beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME)?&& ?????????beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME,?ConversionService.class))?{ ??????beanFactory.setConversionService( ????????????beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME,?ConversionService.class)); ???}???//?Register?a?default?embedded?value?resolver?if?no?bean?post-processor ???//?(such?as?a?PropertyPlaceholderConfigurer?bean)?registered?any?before: ???//?at?this?point,?primarily?for?resolution?in?annotation?attribute?values. ???if?(!beanFactory.hasEmbeddedValueResolver())?{ ??????beanFactory.addEmbeddedValueResolver(new?StringValueResolver()?{?????????@Override ?????????public?String?resolveStringValue(String?strVal)?{????????????return?getEnvironment().resolvePlaceholders(strVal); ?????????} ??????}); ???}???//?先初始化?LoadTimeWeaverAware?類型的?Bean ???//?之前也說過,這是?AspectJ?相關(guān)的內(nèi)容,放心跳過吧 ???String[]?weaverAwareNames?=?beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class,?false,?false);???for?(String?weaverAwareName?:?weaverAwareNames)?{ ??????getBean(weaverAwareName); ???}???//?Stop?using?the?temporary?ClassLoader?for?type?matching. ???beanFactory.setTempClassLoader(null);???//?沒什么別的目的,因?yàn)榈竭@一步的時(shí)候,Spring?已經(jīng)開始預(yù)初始化?singleton?beans?了, ???//?肯定不希望這個(gè)時(shí)候還出現(xiàn)?bean?定義解析、加載、注冊(cè)。 ???beanFactory.freezeConfiguration();???//?開始初始化 ???beanFactory.preInstantiateSingletons(); }
從上面最后一行往里看,我們就又回到 DefaultListableBeanFactory 這個(gè)類了,這個(gè)類大家應(yīng)該都不陌生了吧。
// DefaultListableBeanFactory 728
@Overridepublic?void?preInstantiateSingletons()?throws?BeansException?{???if?(this.logger.isDebugEnabled())?{??????this.logger.debug("Pre-instantiating?singletons?in?"?+?this); ???}???//?this.beanDefinitionNames?保存了所有的?beanNames ???List<String>?beanNames?=?new?ArrayList<String>(this.beanDefinitionNames);???//?觸發(fā)所有的非懶加載的?singleton?beans?的初始化操作 ???for?(String?beanName?:?beanNames)?{??????//?合并父?Bean?中的配置,注意?<bean?id=""?class=""?parent=""?/>?中的?parent,用的不多吧, ??????//?考慮到這可能會(huì)影響大家的理解,我在附錄中解釋了一下?"Bean?繼承",不了解的請(qǐng)到附錄中看一下 ??????RootBeanDefinition?bd?=?getMergedLocalBeanDefinition(beanName);??????//?非抽象、非懶加載的?singletons。如果配置了?'abstract?=?true',那是不需要初始化的 ??????if?(!bd.isAbstract()?&&?bd.isSingleton()?&&?!bd.isLazyInit())?{?????????//?處理?FactoryBean(讀者如果不熟悉?FactoryBean,請(qǐng)移步附錄區(qū)了解) ?????????if?(isFactoryBean(beanName))?{????????????//?FactoryBean?的話,在?beanName?前面加上?‘&’?符號(hào)。再調(diào)用?getBean,getBean?方法別急 ????????????final?FactoryBean<?>?factory?=?(FactoryBean<?>)?getBean(FACTORY_BEAN_PREFIX?+?beanName);????????????//?判斷當(dāng)前?FactoryBean?是否是?SmartFactoryBean?的實(shí)現(xiàn),此處忽略,直接跳過 ????????????boolean?isEagerInit;????????????if?(System.getSecurityManager()?!=?null?&&?factory?instanceof?SmartFactoryBean)?{ ???????????????isEagerInit?=?AccessController.doPrivileged(new?PrivilegedAction<Boolean>()?{??????????????????@Override ??????????????????public?Boolean?run()?{?????????????????????return?((SmartFactoryBean<?>)?factory).isEagerInit(); ??????????????????} ???????????????},?getAccessControlContext()); ????????????}????????????else?{ ???????????????isEagerInit?=?(factory?instanceof?SmartFactoryBean?&& ?????????????????????((SmartFactoryBean<?>)?factory).isEagerInit()); ????????????}????????????if?(isEagerInit)?{ ???????????????getBean(beanName); ????????????} ?????????}?????????else?{????????????//?對(duì)于普通的?Bean,只要調(diào)用?getBean(beanName)?這個(gè)方法就可以進(jìn)行初始化了 ????????????getBean(beanName); ?????????} ??????} ???}???//?到這里說明所有的非懶加載的?singleton?beans?已經(jīng)完成了初始化 ???//?如果我們定義的?bean?是實(shí)現(xiàn)了?SmartInitializingSingleton?接口的,那么在這里得到回調(diào),忽略 ???for?(String?beanName?:?beanNames)?{ ??????Object?singletonInstance?=?getSingleton(beanName);??????if?(singletonInstance?instanceof?SmartInitializingSingleton)?{?????????final?SmartInitializingSingleton?smartSingleton?=?(SmartInitializingSingleton)?singletonInstance;?????????if?(System.getSecurityManager()?!=?null)?{ ????????????AccessController.doPrivileged(new?PrivilegedAction<Object>()?{???????????????@Override ???????????????public?Object?run()?{ ??????????????????smartSingleton.afterSingletonsInstantiated();??????????????????return?null; ???????????????} ????????????},?getAccessControlContext()); ?????????}?????????else?{ ????????????smartSingleton.afterSingletonsInstantiated(); ?????????} ??????} ???} }
接下來,我們就進(jìn)入到 getBean(beanName) 方法了,這個(gè)方法我們經(jīng)常用來從 BeanFactory 中獲取一個(gè) Bean,而初始化的過程也封裝到了這個(gè)方法里。
在繼續(xù)前進(jìn)之前,讀者應(yīng)該具備 FactoryBean 的知識(shí),如果讀者還不熟悉,請(qǐng)移步附錄部分了解 FactoryBean。
// AbstractBeanFactory 196
@Overridepublic?Object?getBean(String?name)?throws?BeansException?{???return?doGetBean(name,?null,?null,?false); }//?我們?cè)谄饰龀跏蓟?Bean?的過程,但是?getBean?方法我們經(jīng)常是用來從容器中獲取?Bean?用的,注意切換思路,//?已經(jīng)初始化過了就從容器中直接返回,否則就先初始化再返回@SuppressWarnings("unchecked")protected?<T>?T?doGetBean(??????final?String?name,?final?Class<T>?requiredType,?final?Object[]?args,?boolean?typeCheckOnly) ??????throws?BeansException?{???//?獲取一個(gè)?“正統(tǒng)的”?beanName,處理兩種情況,一個(gè)是前面說的?FactoryBean(前面帶?‘&’), ???//?一個(gè)是別名問題,因?yàn)檫@個(gè)方法是?getBean,獲取?Bean?用的,你要是傳一個(gè)別名進(jìn)來,是完全可以的 ???final?String?beanName?=?transformedBeanName(name);???//?注意跟著這個(gè),這個(gè)是返回值 ???Object?bean;? ???//?檢查下是不是已經(jīng)創(chuàng)建過了 ???Object?sharedInstance?=?getSingleton(beanName);???//?這里說下?args?唄,雖然看上去一點(diǎn)不重要。前面我們一路進(jìn)來的時(shí)候都是?getBean(beanName), ???//?所以?args?傳參其實(shí)是?null?的,但是如果?args?不為空的時(shí)候,那么意味著調(diào)用方不是希望獲取?Bean,而是創(chuàng)建?Bean ???if?(sharedInstance?!=?null?&&?args?==?null)?{??????if?(logger.isDebugEnabled())?{?????????if?(isSingletonCurrentlyInCreation(beanName))?{ ????????????logger.debug("..."); ?????????}?????????else?{ ????????????logger.debug("Returning?cached?instance?of?singleton?bean?'"?+?beanName?+?"'"); ?????????} ??????}??????//?下面這個(gè)方法:如果是普通?Bean?的話,直接返回?sharedInstance, ??????//?如果是?FactoryBean?的話,返回它創(chuàng)建的那個(gè)實(shí)例對(duì)象 ??????//?(FactoryBean?知識(shí),讀者若不清楚請(qǐng)移步附錄) ??????bean?=?getObjectForBeanInstance(sharedInstance,?name,?beanName,?null); ???}???else?{??????if?(isPrototypeCurrentlyInCreation(beanName))?{?????????//?創(chuàng)建過了此?beanName?的?prototype?類型的?bean,那么拋異常, ?????????//?往往是因?yàn)橄萑肓搜h(huán)引用 ?????????throw?new?BeanCurrentlyInCreationException(beanName); ??????}??????//?檢查一下這個(gè)?BeanDefinition?在容器中是否存在 ??????BeanFactory?parentBeanFactory?=?getParentBeanFactory();??????if?(parentBeanFactory?!=?null?&&?!containsBeanDefinition(beanName))?{?????????//?如果當(dāng)前容器不存在這個(gè)?BeanDefinition,試試父容器中有沒有 ?????????String?nameToLookup?=?originalBeanName(name);?????????if?(args?!=?null)?{????????????//?返回父容器的查詢結(jié)果 ????????????return?(T)?parentBeanFactory.getBean(nameToLookup,?args); ?????????}?????????else?{????????????//?No?args?->?delegate?to?standard?getBean?method. ????????????return?parentBeanFactory.getBean(nameToLookup,?requiredType); ?????????} ??????}??????if?(!typeCheckOnly)?{?????????//?typeCheckOnly?為?false,將當(dāng)前?beanName?放入一個(gè)?alreadyCreated?的?Set?集合中。 ?????????markBeanAsCreated(beanName); ??????}??????/* ???????*?稍稍總結(jié)一下: ???????*?到這里的話,要準(zhǔn)備創(chuàng)建?Bean?了,對(duì)于?singleton?的?Bean?來說,容器中還沒創(chuàng)建過此?Bean; ???????*?對(duì)于?prototype?的?Bean?來說,本來就是要?jiǎng)?chuàng)建一個(gè)新的?Bean。 ???????*/ ??????try?{?????????final?RootBeanDefinition?mbd?=?getMergedLocalBeanDefinition(beanName); ?????????checkMergedBeanDefinition(mbd,?beanName,?args);?????????//?先初始化依賴的所有?Bean,這個(gè)很好理解。 ?????????//?注意,這里的依賴指的是?depends-on?中定義的依賴 ?????????String[]?dependsOn?=?mbd.getDependsOn();?????????if?(dependsOn?!=?null)?{????????????for?(String?dep?:?dependsOn)?{???????????????//?檢查是不是有循環(huán)依賴,這里的循環(huán)依賴和我們前面說的循環(huán)依賴又不一樣,這里肯定是不允許出現(xiàn)的,不然要亂套了,讀者想一下就知道了 ???????????????if?(isDependent(beanName,?dep))?{??????????????????throw?new?BeanCreationException(mbd.getResourceDescription(),?beanName,????????????????????????"Circular?depends-on?relationship?between?'"?+?beanName?+?"'?and?'"?+?dep?+?"'"); ???????????????}???????????????//?注冊(cè)一下依賴關(guān)系 ???????????????registerDependentBean(dep,?beanName);???????????????//?先初始化被依賴項(xiàng) ???????????????getBean(dep); ????????????} ?????????}?????????//?如果是?singleton?scope?的,創(chuàng)建?singleton?的實(shí)例 ?????????if?(mbd.isSingleton())?{ ????????????sharedInstance?=?getSingleton(beanName,?new?ObjectFactory<Object>()?{???????????????@Override ???????????????public?Object?getObject()?throws?BeansException?{??????????????????try?{?????????????????????//?執(zhí)行創(chuàng)建?Bean,詳情后面再說 ?????????????????????return?createBean(beanName,?mbd,?args); ??????????????????}??????????????????catch?(BeansException?ex)?{ ?????????????????????destroySingleton(beanName);?????????????????????throw?ex; ??????????????????} ???????????????} ????????????}); ????????????bean?=?getObjectForBeanInstance(sharedInstance,?name,?beanName,?mbd); ?????????}?????????//?如果是?prototype?scope?的,創(chuàng)建?prototype?的實(shí)例 ?????????else?if?(mbd.isPrototype())?{????????????//?It's?a?prototype?->?create?a?new?instance. ????????????Object?prototypeInstance?=?null;????????????try?{ ???????????????beforePrototypeCreation(beanName);???????????????//?執(zhí)行創(chuàng)建?Bean ???????????????prototypeInstance?=?createBean(beanName,?mbd,?args); ????????????}????????????finally?{ ???????????????afterPrototypeCreation(beanName); ????????????} ????????????bean?=?getObjectForBeanInstance(prototypeInstance,?name,?beanName,?mbd); ?????????}?????????//?如果不是?singleton?和?prototype?的話,需要委托給相應(yīng)的實(shí)現(xiàn)類來處理 ?????????else?{ ????????????String?scopeName?=?mbd.getScope();????????????final?Scope?scope?=?this.scopes.get(scopeName);????????????if?(scope?==?null)?{???????????????throw?new?IllegalStateException("No?Scope?registered?for?scope?name?'"?+?scopeName?+?"'"); ????????????}????????????try?{ ???????????????Object?scopedInstance?=?scope.get(beanName,?new?ObjectFactory<Object>()?{??????????????????@Override ??????????????????public?Object?getObject()?throws?BeansException?{ ?????????????????????beforePrototypeCreation(beanName);?????????????????????try?{????????????????????????//?執(zhí)行創(chuàng)建?Bean ????????????????????????return?createBean(beanName,?mbd,?args); ?????????????????????}?????????????????????finally?{ ????????????????????????afterPrototypeCreation(beanName); ?????????????????????} ??????????????????} ???????????????}); ???????????????bean?=?getObjectForBeanInstance(scopedInstance,?name,?beanName,?mbd); ????????????}????????????catch?(IllegalStateException?ex)?{???????????????throw?new?BeanCreationException(beanName,?????????????????????"Scope?'"?+?scopeName?+?"'?is?not?active?for?the?current?thread;?consider?"?+?????????????????????"defining?a?scoped?proxy?for?this?bean?if?you?intend?to?refer?to?it?from?a?singleton", ?????????????????????ex); ????????????} ?????????} ??????}??????catch?(BeansException?ex)?{ ?????????cleanupAfterBeanCreationFailure(beanName);?????????throw?ex; ??????} ???}???//?最后,檢查一下類型對(duì)不對(duì),不對(duì)的話就拋異常,對(duì)的話就返回了 ???if?(requiredType?!=?null?&&?bean?!=?null?&&?!requiredType.isInstance(bean))?{??????try?{?????????return?getTypeConverter().convertIfNecessary(bean,?requiredType); ??????}??????catch?(TypeMismatchException?ex)?{?????????if?(logger.isDebugEnabled())?{ ????????????logger.debug("Failed?to?convert?bean?'"?+?name?+?"'?to?required?type?'"?+ ??????????????????ClassUtils.getQualifiedName(requiredType)?+?"'",?ex); ?????????}?????????throw?new?BeanNotOfRequiredTypeException(name,?requiredType,?bean.getClass()); ??????} ???}???return?(T)?bean; }
大家應(yīng)該也猜到了,接下來當(dāng)然是分析 createBean 方法:
protected?abstract?Object?createBean(String?beanName,?RootBeanDefinition?mbd,?Object[]?args)?throws?BeanCreationException;
第三個(gè)參數(shù) args 數(shù)組代表創(chuàng)建實(shí)例需要的參數(shù),不就是給構(gòu)造方法用的參數(shù),或者是工廠 Bean 的參數(shù)嘛,不過要注意,在我們的初始化階段,args 是 null。
這回我們要到一個(gè)新的類了 AbstractAutowireCapableBeanFactory,看類名,AutowireCapable?類名是不是也說明了點(diǎn)問題了。
主要是為了以下場景,采用 @Autowired 注解注入屬性值:
public?class?MessageServiceImpl?implements?MessageService?{????@Autowired ????private?UserService?userService;????public?String?getMessage()?{????????return?userService.getMessage(); ????} }
<bean?id="messageService"?class="com.javadoop.example.MessageServiceImpl"?/>
以上這種屬于混用了 xml 和 注解 兩種方式的配置方式,Spring 會(huì)處理這種情況。
好了,讀者要知道這么回事就可以了,繼續(xù)向前。
// AbstractAutowireCapableBeanFactory 447
/** ?*?Central?method?of?this?class:?creates?a?bean?instance, ?*?populates?the?bean?instance,?applies?post-processors,?etc. ?*?@see?#doCreateBean ?*/@Override protected?Object?createBean(String?beanName,?RootBeanDefinition?mbd,?Object[]?args)?throws?BeanCreationException?{???if?(logger.isDebugEnabled())?{ ??????logger.debug("Creating?instance?of?bean?'"?+?beanName?+?"'"); ???} ???RootBeanDefinition?mbdToUse?=?mbd;???//?確保?BeanDefinition?中的?Class?被加載 ???Class<?>?resolvedClass?=?resolveBeanClass(mbd,?beanName);???if?(resolvedClass?!=?null?&&?!mbd.hasBeanClass()?&&?mbd.getBeanClassName()?!=?null)?{ ??????mbdToUse?=?new?RootBeanDefinition(mbd); ??????mbdToUse.setBeanClass(resolvedClass); ???}???//?準(zhǔn)備方法覆寫,這里又涉及到一個(gè)概念:MethodOverrides,它來自于?bean?定義中的?<lookup-method?/>? ???//?和?<replaced-method?/>,如果讀者感興趣,回到?bean?解析的地方看看對(duì)這兩個(gè)標(biāo)簽的解析。 ???//?我在附錄中也對(duì)這兩個(gè)標(biāo)簽的相關(guān)知識(shí)點(diǎn)進(jìn)行了介紹,讀者可以移步去看看 ???try?{ ??????mbdToUse.prepareMethodOverrides(); ???}???catch?(BeanDefinitionValidationException?ex)?{??????throw?new?BeanDefinitionStoreException(mbdToUse.getResourceDescription(), ????????????beanName,?"Validation?of?method?overrides?failed",?ex); ???}???try?{??????//?讓?InstantiationAwareBeanPostProcessor?在這一步有機(jī)會(huì)返回代理, ??????//?在?《Spring?AOP?源碼分析》那篇文章中有解釋,這里先跳過 ??????Object?bean?=?resolveBeforeInstantiation(beanName,?mbdToUse);??????if?(bean?!=?null)?{?????????return?bean;? ??????} ???}???catch?(Throwable?ex)?{??????throw?new?BeanCreationException(mbdToUse.getResourceDescription(),?beanName,????????????"BeanPostProcessor?before?instantiation?of?bean?failed",?ex); ???}???//?重頭戲,創(chuàng)建?bean ???Object?beanInstance?=?doCreateBean(beanName,?mbdToUse,?args);???if?(logger.isDebugEnabled())?{ ??????logger.debug("Finished?creating?instance?of?bean?'"?+?beanName?+?"'"); ???}???return?beanInstance; }
我們繼續(xù)往里看 doCreateBean 這個(gè)方法:
/** ?*?Actually?create?the?specified?bean.?Pre-creation?processing?has?already?happened ?*?at?this?point,?e.g.?checking?{@code?postProcessBeforeInstantiation}?callbacks. ?*?<p>Differentiates?between?default?bean?instantiation,?use?of?a ?*?factory?method,?and?autowiring?a?constructor. ?*?@param?beanName?the?name?of?the?bean ?*?@param?mbd?the?merged?bean?definition?for?the?bean ?*?@param?args?explicit?arguments?to?use?for?constructor?or?factory?method?invocation ?*?@return?a?new?instance?of?the?bean ?*?@throws?BeanCreationException?if?the?bean?could?not?be?created ?*?@see?#instantiateBean ?*?@see?#instantiateUsingFactoryMethod ?*?@see?#autowireConstructor ?*/protected?Object?doCreateBean(final?String?beanName,?final?RootBeanDefinition?mbd,?final?Object[]?args) ??????throws?BeanCreationException?{???//?Instantiate?the?bean. ???BeanWrapper?instanceWrapper?=?null;???if?(mbd.isSingleton())?{ ??????instanceWrapper?=?this.factoryBeanInstanceCache.remove(beanName); ???}???if?(instanceWrapper?==?null)?{??????//?說明不是?FactoryBean,這里實(shí)例化?Bean,這里非常關(guān)鍵,細(xì)節(jié)之后再說 ??????instanceWrapper?=?createBeanInstance(beanName,?mbd,?args); ???}???//?這個(gè)就是?Bean?里面的?我們定義的類?的實(shí)例,很多地方我直接描述成?"bean?實(shí)例" ???final?Object?bean?=?(instanceWrapper?!=?null???instanceWrapper.getWrappedInstance()?:?null);???//?類型 ???Class<?>?beanType?=?(instanceWrapper?!=?null???instanceWrapper.getWrappedClass()?:?null); ???mbd.resolvedTargetType?=?beanType;???//?建議跳過吧,涉及接口:MergedBeanDefinitionPostProcessor ???synchronized?(mbd.postProcessingLock)?{??????if?(!mbd.postProcessed)?{?????????try?{????????????//?MergedBeanDefinitionPostProcessor,這個(gè)我真不展開說了,直接跳過吧,很少用的 ????????????applyMergedBeanDefinitionPostProcessors(mbd,?beanType,?beanName); ?????????}?????????catch?(Throwable?ex)?{????????????throw?new?BeanCreationException(mbd.getResourceDescription(),?beanName,??????????????????"Post-processing?of?merged?bean?definition?failed",?ex); ?????????} ?????????mbd.postProcessed?=?true; ??????} ???}???//?Eagerly?cache?singletons?to?be?able?to?resolve?circular?references ???//?even?when?triggered?by?lifecycle?interfaces?like?BeanFactoryAware. ???//?下面這塊代碼是為了解決循環(huán)依賴的問題,以后有時(shí)間,我再對(duì)循環(huán)依賴這個(gè)問題進(jìn)行解析吧 ???boolean?earlySingletonExposure?=?(mbd.isSingleton()?&&?this.allowCircularReferences?&& ?????????isSingletonCurrentlyInCreation(beanName));???if?(earlySingletonExposure)?{??????if?(logger.isDebugEnabled())?{ ?????????logger.debug("Eagerly?caching?bean?'"?+?beanName?+???????????????"'?to?allow?for?resolving?potential?circular?references"); ??????} ??????addSingletonFactory(beanName,?new?ObjectFactory<Object>()?{?????????@Override ?????????public?Object?getObject()?throws?BeansException?{????????????return?getEarlyBeanReference(beanName,?mbd,?bean); ?????????} ??????}); ???}???//?Initialize?the?bean?instance. ???Object?exposedObject?=?bean;???try?{??????//?這一步也是非常關(guān)鍵的,這一步負(fù)責(zé)屬性裝配,因?yàn)榍懊娴膶?shí)例只是實(shí)例化了,并沒有設(shè)值,這里就是設(shè)值 ??????populateBean(beanName,?mbd,?instanceWrapper);??????if?(exposedObject?!=?null)?{?????????//?還記得?init-method?嗎?還有?InitializingBean?接口?還有?BeanPostProcessor?接口? ?????????//?這里就是處理?bean?初始化完成后的各種回調(diào) ?????????exposedObject?=?initializeBean(beanName,?exposedObject,?mbd); ??????} ???}???catch?(Throwable?ex)?{??????if?(ex?instanceof?BeanCreationException?&&?beanName.equals(((BeanCreationException)?ex).getBeanName()))?{?????????throw?(BeanCreationException)?ex; ??????}??????else?{?????????throw?new?BeanCreationException( ???????????????mbd.getResourceDescription(),?beanName,?"Initialization?of?bean?failed",?ex); ??????} ???}???if?(earlySingletonExposure)?{??????//? ??????Object?earlySingletonReference?=?getSingleton(beanName,?false);??????if?(earlySingletonReference?!=?null)?{?????????if?(exposedObject?==?bean)?{ ????????????exposedObject?=?earlySingletonReference; ?????????}?????????else?if?(!this.allowRawInjectionDespiteWrapping?&&?hasDependentBean(beanName))?{ ????????????String[]?dependentBeans?=?getDependentBeans(beanName); ????????????Set<String>?actualDependentBeans?=?new?LinkedHashSet<String>(dependentBeans.length);????????????for?(String?dependentBean?:?dependentBeans)?{???????????????if?(!removeSingletonIfCreatedForTypeCheckOnly(dependentBean))?{ ??????????????????actualDependentBeans.add(dependentBean); ???????????????} ????????????}????????????if?(!actualDependentBeans.isEmpty())?{???????????????throw?new?BeanCurrentlyInCreationException(beanName,?????????????????????"Bean?with?name?'"?+?beanName?+?"'?has?been?injected?into?other?beans?["?+ ?????????????????????StringUtils.collectionToCommaDelimitedString(actualDependentBeans)?+?????????????????????"]?in?its?raw?version?as?part?of?a?circular?reference,?but?has?eventually?been?"?+?????????????????????"wrapped.?This?means?that?said?other?beans?do?not?use?the?final?version?of?the?"?+?????????????????????"bean.?This?is?often?the?result?of?over-eager?type?matching?-?consider?using?"?+?????????????????????"'getBeanNamesOfType'?with?the?'allowEagerInit'?flag?turned?off,?for?example."); ????????????} ?????????} ??????} ???}???//?Register?bean?as?disposable. ???try?{ ??????registerDisposableBeanIfNecessary(beanName,?bean,?mbd); ???}???catch?(BeanDefinitionValidationException?ex)?{??????throw?new?BeanCreationException( ????????????mbd.getResourceDescription(),?beanName,?"Invalid?destruction?signature",?ex); ???}???return?exposedObject; }
到這里,我們已經(jīng)分析完了 doCreateBean 方法,總的來說,我們已經(jīng)說完了整個(gè)初始化流程。
接下來我們挑 doCreateBean 中的三個(gè)細(xì)節(jié)出來說說。一個(gè)是創(chuàng)建 Bean 實(shí)例的 createBeanInstance 方法,一個(gè)是依賴注入的 populateBean 方法,還有就是回調(diào)方法 initializeBean。
注意了,接下來的這三個(gè)方法要認(rèn)真說那也是極其復(fù)雜的,很多地方我就點(diǎn)到為止了,感興趣的讀者可以自己往里看,最好就是碰到不懂的,自己寫代碼去調(diào)試它。
創(chuàng)建 Bean 實(shí)例
我們先看看 createBeanInstance 方法。需要說明的是,這個(gè)方法如果每個(gè)分支都分析下去,必然也是極其復(fù)雜冗長的,我們挑重點(diǎn)說。此方法的目的就是實(shí)例化我們指定的類。
protected?BeanWrapper?createBeanInstance(String?beanName,?RootBeanDefinition?mbd,?Object[]?args)?{???//?確保已經(jīng)加載了此?class ???Class<?>?beanClass?=?resolveBeanClass(mbd,?beanName);???//?校驗(yàn)一下這個(gè)類的訪問權(quán)限 ???if?(beanClass?!=?null?&&?!Modifier.isPublic(beanClass.getModifiers())?&&?!mbd.isNonPublicAccessAllowed())?{??????throw?new?BeanCreationException(mbd.getResourceDescription(),?beanName,????????????"Bean?class?isn't?public,?and?non-public?access?not?allowed:?"?+?beanClass.getName()); ???}???if?(mbd.getFactoryMethodName()?!=?null)??{??????//?采用工廠方法實(shí)例化,不熟悉這個(gè)概念的讀者請(qǐng)看附錄,注意,不是?FactoryBean ??????return?instantiateUsingFactoryMethod(beanName,?mbd,?args); ???}???//?如果不是第一次創(chuàng)建,比如第二次創(chuàng)建?prototype?bean。 ???//?這種情況下,我們可以從第一次創(chuàng)建知道,采用無參構(gòu)造函數(shù),還是構(gòu)造函數(shù)依賴注入?來完成實(shí)例化 ???boolean?resolved?=?false;???boolean?autowireNecessary?=?false;???if?(args?==?null)?{??????synchronized?(mbd.constructorArgumentLock)?{?????????if?(mbd.resolvedConstructorOrFactoryMethod?!=?null)?{ ????????????resolved?=?true; ????????????autowireNecessary?=?mbd.constructorArgumentsResolved; ?????????} ??????} ???}???if?(resolved)?{??????if?(autowireNecessary)?{?????????//?構(gòu)造函數(shù)依賴注入 ?????????return?autowireConstructor(beanName,?mbd,?null,?null); ??????}??????else?{?????????//?無參構(gòu)造函數(shù) ?????????return?instantiateBean(beanName,?mbd); ??????} ???}???//?判斷是否采用有參構(gòu)造函數(shù) ???Constructor<?>[]?ctors?=?determineConstructorsFromBeanPostProcessors(beanClass,?beanName);???if?(ctors?!=?null?|| ?????????mbd.getResolvedAutowireMode()?==?RootBeanDefinition.AUTOWIRE_CONSTRUCTOR?|| ?????????mbd.hasConstructorArgumentValues()?||?!ObjectUtils.isEmpty(args))??{??????//?構(gòu)造函數(shù)依賴注入 ??????return?autowireConstructor(beanName,?mbd,?ctors,?args); ???}???//?調(diào)用無參構(gòu)造函數(shù) ???return?instantiateBean(beanName,?mbd); }
挑個(gè)簡單的無參構(gòu)造函數(shù)構(gòu)造實(shí)例來看看:
protected?BeanWrapper?instantiateBean(final?String?beanName,?final?RootBeanDefinition?mbd)?{???try?{ ??????Object?beanInstance;??????final?BeanFactory?parent?=?this;??????if?(System.getSecurityManager()?!=?null)?{ ?????????beanInstance?=?AccessController.doPrivileged(new?PrivilegedAction<Object>()?{????????????@Override ????????????public?Object?run()?{???????????????return?getInstantiationStrategy().instantiate(mbd,?beanName,?parent); ????????????} ?????????},?getAccessControlContext()); ??????}??????else?{?????????//?實(shí)例化 ?????????beanInstance?=?getInstantiationStrategy().instantiate(mbd,?beanName,?parent); ??????}??????//?包裝一下,返回 ??????BeanWrapper?bw?=?new?BeanWrapperImpl(beanInstance); ??????initBeanWrapper(bw);??????return?bw; ???}???catch?(Throwable?ex)?{??????throw?new?BeanCreationException( ????????????mbd.getResourceDescription(),?beanName,?"Instantiation?of?bean?failed",?ex); ???} }
我們可以看到,關(guān)鍵的地方在于:
beanInstance?=?getInstantiationStrategy().instantiate(mbd,?beanName,?parent);
這里會(huì)進(jìn)行實(shí)際的實(shí)例化過程,我們進(jìn)去看看:
// SimpleInstantiationStrategy 59
@Overridepublic?Object?instantiate(RootBeanDefinition?bd,?String?beanName,?BeanFactory?owner)?{???//?如果不存在方法覆寫,那就使用?java?反射進(jìn)行實(shí)例化,否則使用?CGLIB, ???//?方法覆寫?請(qǐng)參見附錄"方法注入"中對(duì)?lookup-method?和?replaced-method?的介紹 ???if?(bd.getMethodOverrides().isEmpty())?{ ??????Constructor<?>?constructorToUse;??????synchronized?(bd.constructorArgumentLock)?{ ?????????constructorToUse?=?(Constructor<?>)?bd.resolvedConstructorOrFactoryMethod;?????????if?(constructorToUse?==?null)?{????????????final?Class<?>?clazz?=?bd.getBeanClass();????????????if?(clazz.isInterface())?{???????????????throw?new?BeanInstantiationException(clazz,?"Specified?class?is?an?interface"); ????????????}????????????try?{???????????????if?(System.getSecurityManager()?!=?null)?{ ??????????????????constructorToUse?=?AccessController.doPrivileged(new?PrivilegedExceptionAction<Constructor<?>>()?{?????????????????????@Override ?????????????????????public?Constructor<?>?run()?throws?Exception?{????????????????????????return?clazz.getDeclaredConstructor((Class[])?null); ?????????????????????} ??????????????????}); ???????????????}???????????????else?{ ??????????????????constructorToUse?=?clazz.getDeclaredConstructor((Class[])?null); ???????????????} ???????????????bd.resolvedConstructorOrFactoryMethod?=?constructorToUse; ????????????}????????????catch?(Throwable?ex)?{???????????????throw?new?BeanInstantiationException(clazz,?"No?default?constructor?found",?ex); ????????????} ?????????} ??????}??????//?利用構(gòu)造方法進(jìn)行實(shí)例化 ??????return?BeanUtils.instantiateClass(constructorToUse); ???}???else?{??????//?存在方法覆寫,利用?CGLIB?來完成實(shí)例化,需要依賴于?CGLIB?生成子類,這里就不展開了。 ??????//?tips:?因?yàn)槿绻皇褂?CGLIB?的話,存在?override?的情況?JDK?并沒有提供相應(yīng)的實(shí)例化支持 ??????return?instantiateWithMethodInjection(bd,?beanName,?owner); ???} }
到這里,我們就算實(shí)例化完成了。我們開始說怎么進(jìn)行屬性注入。
bean 屬性注入
看完了 createBeanInstance(...) 方法,我們來看看 populateBean(...) 方法,該方法負(fù)責(zé)進(jìn)行屬性設(shè)值,處理依賴。
// AbstractAutowireCapableBeanFactory 1203
protected?void?populateBean(String?beanName,?RootBeanDefinition?mbd,?BeanWrapper?bw)?{???//?bean?實(shí)例的所有屬性都在這里了 ???PropertyValues?pvs?=?mbd.getPropertyValues();???if?(bw?==?null)?{??????if?(!pvs.isEmpty())?{?????????throw?new?BeanCreationException( ???????????????mbd.getResourceDescription(),?beanName,?"Cannot?apply?property?values?to?null?instance"); ??????}??????else?{?????????//?Skip?property?population?phase?for?null?instance. ?????????return; ??????} ???}???//?到這步的時(shí)候,bean?實(shí)例化完成(通過工廠方法或構(gòu)造方法),但是還沒開始屬性設(shè)值, ???//?InstantiationAwareBeanPostProcessor?的實(shí)現(xiàn)類可以在這里對(duì)?bean?進(jìn)行狀態(tài)修改, ???//?我也沒找到有實(shí)際的使用,所以我們暫且忽略這塊吧 ???boolean?continueWithPropertyPopulation?=?true;???if?(!mbd.isSynthetic()?&&?hasInstantiationAwareBeanPostProcessors())?{??????for?(BeanPostProcessor?bp?:?getBeanPostProcessors())?{?????????if?(bp?instanceof?InstantiationAwareBeanPostProcessor)?{ ????????????InstantiationAwareBeanPostProcessor?ibp?=?(InstantiationAwareBeanPostProcessor)?bp;????????????//?如果返回?false,代表不需要進(jìn)行后續(xù)的屬性設(shè)值,也不需要再經(jīng)過其他的?BeanPostProcessor?的處理 ????????????if?(!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(),?beanName))?{ ???????????????continueWithPropertyPopulation?=?false;???????????????break; ????????????} ?????????} ??????} ???}???if?(!continueWithPropertyPopulation)?{??????return; ???}???if?(mbd.getResolvedAutowireMode()?==?RootBeanDefinition.AUTOWIRE_BY_NAME?|| ?????????mbd.getResolvedAutowireMode()?==?RootBeanDefinition.AUTOWIRE_BY_TYPE)?{ ??????MutablePropertyValues?newPvs?=?new?MutablePropertyValues(pvs);??????//?通過名字找到所有屬性值,如果是?bean?依賴,先初始化依賴的?bean。記錄依賴關(guān)系 ??????if?(mbd.getResolvedAutowireMode()?==?RootBeanDefinition.AUTOWIRE_BY_NAME)?{ ?????????autowireByName(beanName,?mbd,?bw,?newPvs); ??????}??????//?通過類型裝配。復(fù)雜一些 ??????if?(mbd.getResolvedAutowireMode()?==?RootBeanDefinition.AUTOWIRE_BY_TYPE)?{ ?????????autowireByType(beanName,?mbd,?bw,?newPvs); ??????} ??????pvs?=?newPvs; ???}???boolean?hasInstAwareBpps?=?hasInstantiationAwareBeanPostProcessors();???boolean?needsDepCheck?=?(mbd.getDependencyCheck()?!=?RootBeanDefinition.DEPENDENCY_CHECK_NONE);???if?(hasInstAwareBpps?||?needsDepCheck)?{ ??????PropertyDescriptor[]?filteredPds?=?filterPropertyDescriptorsForDependencyCheck(bw,?mbd.allowCaching);??????if?(hasInstAwareBpps)?{?????????for?(BeanPostProcessor?bp?:?getBeanPostProcessors())?{????????????if?(bp?instanceof?InstantiationAwareBeanPostProcessor)?{ ???????????????InstantiationAwareBeanPostProcessor?ibp?=?(InstantiationAwareBeanPostProcessor)?bp;???????????????//?這里有個(gè)非常有用的?BeanPostProcessor?進(jìn)到這里:?AutowiredAnnotationBeanPostProcessor ???????????????//?對(duì)采用?@Autowired、@Value?注解的依賴進(jìn)行設(shè)值,這里的內(nèi)容也是非常豐富的,不過本文不會(huì)展開說了,感興趣的讀者請(qǐng)自行研究 ???????????????pvs?=?ibp.postProcessPropertyValues(pvs,?filteredPds,?bw.getWrappedInstance(),?beanName);???????????????if?(pvs?==?null)?{??????????????????return; ???????????????} ????????????} ?????????} ??????}??????if?(needsDepCheck)?{ ?????????checkDependencies(beanName,?mbd,?filteredPds,?pvs); ??????} ???}???//?設(shè)置?bean?實(shí)例的屬性值 ???applyPropertyValues(beanName,?mbd,?bw,?pvs); }
initializeBean
屬性注入完成后,這一步其實(shí)就是處理各種回調(diào)了,這塊代碼比較簡單。
protected?Object?initializeBean(final?String?beanName,?final?Object?bean,?RootBeanDefinition?mbd)?{???if?(System.getSecurityManager()?!=?null)?{ ??????AccessController.doPrivileged(new?PrivilegedAction<Object>()?{?????????@Override ?????????public?Object?run()?{ ????????????invokeAwareMethods(beanName,?bean);????????????return?null; ?????????} ??????},?getAccessControlContext()); ???}???else?{??????//?如果?bean?實(shí)現(xiàn)了?BeanNameAware、BeanClassLoaderAware?或?BeanFactoryAware?接口,回調(diào) ??????invokeAwareMethods(beanName,?bean); ???} ???Object?wrappedBean?=?bean;???if?(mbd?==?null?||?!mbd.isSynthetic())?{??????//?BeanPostProcessor?的?postProcessBeforeInitialization?回調(diào) ??????wrappedBean?=?applyBeanPostProcessorsBeforeInitialization(wrappedBean,?beanName); ???}???try?{??????//?處理?bean?中定義的?init-method, ??????//?或者如果?bean?實(shí)現(xiàn)了?InitializingBean?接口,調(diào)用?afterPropertiesSet()?方法 ??????invokeInitMethods(beanName,?wrappedBean,?mbd); ???}???catch?(Throwable?ex)?{??????throw?new?BeanCreationException( ????????????(mbd?!=?null???mbd.getResourceDescription()?:?null), ????????????beanName,?"Invocation?of?init?method?failed",?ex); ???}???if?(mbd?==?null?||?!mbd.isSynthetic())?{??????//?BeanPostProcessor?的?postProcessAfterInitialization?回調(diào) ??????wrappedBean?=?applyBeanPostProcessorsAfterInitialization(wrappedBean,?beanName); ???}???return?wrappedBean; }
大家發(fā)現(xiàn)沒有,BeanPostProcessor 的兩個(gè)回調(diào)都發(fā)生在這邊,只不過中間處理了 init-method,是不是和讀者原來的認(rèn)知有點(diǎn)不一樣了?
每個(gè) Bean 在 Spring 容器中都有一個(gè)唯一的名字(beanName)和 0 個(gè)或多個(gè)別名(aliases)。
我們從 Spring 容器中獲取 Bean 的時(shí)候,可以根據(jù) beanName,也可以通過別名。
beanFactory.getBean("beanName?or?alias");
在配置?<bean />
?的過程中,我們可以配置 id 和 name,看幾個(gè)例子就知道是怎么回事了。
<bean?id="messageService"?name="m1,?m2,?m3"?class="com.javadoop.example.MessageServiceImpl">
以上配置的結(jié)果就是:beanName 為 messageService,別名有 3 個(gè),分別為 m1、m2、m3。
<bean?name="m1,?m2,?m3"?class="com.javadoop.example.MessageServiceImpl"?/>
以上配置的結(jié)果就是:beanName 為 m1,別名有 2 個(gè),分別為 m2、m3。
<bean?class="com.javadoop.example.MessageServiceImpl">
beanName 為:com.javadoop.example.MessageServiceImpl#0,
別名 1 個(gè),為: com.javadoop.example.MessageServiceImpl
<bean?id="messageService"?class="com.javadoop.example.MessageServiceImpl">
以上配置的結(jié)果就是:beanName 為 messageService,沒有別名。
我們說過,默認(rèn)情況下,allowBeanDefinitionOverriding 屬性為 null。如果在同一配置文件中 Bean id 或 name 重復(fù)了,會(huì)拋錯(cuò),但是如果不是同一配置文件中,會(huì)發(fā)生覆蓋。
可是有些時(shí)候我們希望在系統(tǒng)啟動(dòng)的過程中就嚴(yán)格杜絕發(fā)生 Bean 覆蓋,因?yàn)槿f一出現(xiàn)這種情況,會(huì)增加我們排查問題的成本。
循環(huán)依賴說的是 A 依賴 B,而 B 又依賴 A?;蛘呤?A 依賴 B,B 依賴 C,而 C 卻依賴 A。默認(rèn) allowCircularReferences 也是 null。
它們兩個(gè)屬性是一起出現(xiàn)的,必然可以在同一個(gè)地方一起進(jìn)行配置。
添加這兩個(gè)屬性的作者 Juergen Hoeller 在這個(gè)?jira?的討論中說明了怎么配置這兩個(gè)屬性。
public?class?NoBeanOverridingContextLoader?extends?ContextLoader?{??@Override ??protected?void?customizeContext(ServletContext?servletContext,?ConfigurableWebApplicationContext?applicationContext)?{????super.customizeContext(servletContext,?applicationContext); ????AbstractRefreshableApplicationContext?arac?=?(AbstractRefreshableApplicationContext)?applicationContext; ????arac.setAllowBeanDefinitionOverriding(false); ??} }
public?class?MyContextLoaderListener?extends?org.springframework.web.context.ContextLoaderListener?{??@Override ??protected?ContextLoader?createContextLoader()?{????return?new?NoBeanOverridingContextLoader(); ??} }
<listener>????<listener-class>com.javadoop.MyContextLoaderListener</listener-class>??</listener>
如果以上方式不能滿足你的需求,請(qǐng)參考這個(gè)鏈接:解決spring中不同配置文件中存在name或者id相同的bean可能引起的問題
我們可以把不同環(huán)境的配置分別配置到單獨(dú)的文件中,舉個(gè)例子:
<beans?profile="development" ????xmlns="http://www.springframework.org/schema/beans" ????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ????xmlns:jdbc="http://www.springframework.org/schema/jdbc" ????xsi:schemaLocation="..."> ????<jdbc:embedded-database?id="dataSource"> ????????<jdbc:script?location="classpath:com/bank/config/sql/schema.sql"/> ????????<jdbc:script?location="classpath:com/bank/config/sql/test-data.sql"/> ????</jdbc:embedded-database></beans>
<beans?profile="production" ????xmlns="http://www.springframework.org/schema/beans" ????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ????xmlns:jee="http://www.springframework.org/schema/jee" ????xsi:schemaLocation="...">????<jee:jndi-lookup?id="dataSource"?jndi-name="java:comp/env/jdbc/datasource"/></beans>
應(yīng)該不必做過多解釋了吧,看每個(gè)文件第一行的 profile=""。
當(dāng)然,我們也可以在一個(gè)配置文件中使用:
<beans?xmlns="http://www.springframework.org/schema/beans" ????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ????xmlns:jdbc="http://www.springframework.org/schema/jdbc" ????xmlns:jee="http://www.springframework.org/schema/jee" ????xsi:schemaLocation="..."> ????<beans?profile="development"> ????????<jdbc:embedded-database?id="dataSource"> ????????????<jdbc:script?location="classpath:com/bank/config/sql/schema.sql"/> ????????????<jdbc:script?location="classpath:com/bank/config/sql/test-data.sql"/> ????????</jdbc:embedded-database> ????</beans> ????<beans?profile="production"> ????????<jee:jndi-lookup?id="dataSource"?jndi-name="java:comp/env/jdbc/datasource"/> ????</beans></beans>
理解起來也很簡單吧。
接下來的問題是,怎么使用特定的 profile 呢?Spring 在啟動(dòng)的過程中,會(huì)去尋找 “spring.profiles.active” 的屬性值,根據(jù)這個(gè)屬性值來的。那怎么配置這個(gè)值呢?
Spring 會(huì)在這幾個(gè)地方尋找 spring.profiles.active 的屬性值:操作系統(tǒng)環(huán)境變量、JVM 系統(tǒng)變量、web.xml 中定義的參數(shù)、JNDI。
最簡單的方式莫過于在程序啟動(dòng)的時(shí)候指定:
-Dspring.profiles.active="profile1,profile2"
profile 可以激活多個(gè)
當(dāng)然,我們也可以通過代碼的形式從 Environment 中設(shè)置 profile:
AnnotationConfigApplicationContext?ctx?=?new?AnnotationConfigApplicationContext(); ctx.getEnvironment().setActiveProfiles("development"); ctx.register(SomeConfig.class,?StandaloneDataConfig.class,?JndiDataConfig.class); ctx.refresh();?//?重啟
如果是 Spring Boot 的話更簡單,我們一般會(huì)創(chuàng)建 application.properties、application-dev.properties、application-prod.properties 等文件,其中 application.properties 配置各個(gè)環(huán)境通用的配置,application-{profile}.properties 中配置特定環(huán)境的配置,然后在啟動(dòng)的時(shí)候指定 profile:
java?-Dspring.profiles.active=prod?-jar?JavaDoop.jar
如果是單元測試中使用的話,在測試類中使用 @ActiveProfiles 指定,這里就不展開了。
請(qǐng)讀者注意 factory-bean 和 FactoryBean 的區(qū)別。這節(jié)說的是前者,是說靜態(tài)工廠或?qū)嵗S,而后者是 Spring 中的特殊接口,代表一類特殊的 Bean,附錄的下面一節(jié)會(huì)介紹 FactoryBean。
設(shè)計(jì)模式里,工廠方法模式分靜態(tài)工廠和實(shí)例工廠,我們分別看看 Spring 中怎么配置這兩個(gè),來個(gè)代碼示例就什么都清楚了。
靜態(tài)工廠:
<bean?id="clientService" ????class="examples.ClientService" ????factory-method="createInstance"/>
public?class?ClientService?{????private?static?ClientService?clientService?=?new?ClientService();????private?ClientService()?{}????//?靜態(tài)方法 ????public?static?ClientService?createInstance()?{????????return?clientService; ????} }
實(shí)例工廠:
<bean?id="serviceLocator"?class="examples.DefaultServiceLocator">????<!--?inject?any?dependencies?required?by?this?locator?bean?--></bean><bean?id="clientService" ????factory-bean="serviceLocator" ????factory-method="createClientServiceInstance"/><bean?id="accountService" ????factory-bean="serviceLocator" ????factory-method="createAccountServiceInstance"/>
public?class?DefaultServiceLocator?{????private?static?ClientService?clientService?=?new?ClientServiceImpl();????private?static?AccountService?accountService?=?new?AccountServiceImpl();????public?ClientService?createClientServiceInstance()?{????????return?clientService; ????}????public?AccountService?createAccountServiceInstance()?{????????return?accountService; ????} }
FactoryBean 適用于 Bean 的創(chuàng)建過程比較復(fù)雜的場景,比如數(shù)據(jù)庫連接池的創(chuàng)建。
public?interface?FactoryBean<T>?{????T?getObject()?throws?Exception;????Class<T>?getObjectType();????boolean?isSingleton(); }
public?class?Person?{? ????private?Car?car?;????private?void?setCar(Car?car){?this.car?=?car;??}?? }
我們假設(shè)現(xiàn)在需要?jiǎng)?chuàng)建一個(gè) Person 的 Bean,首先我們需要一個(gè) Car 的實(shí)例,我們這里假設(shè) Car 的實(shí)例創(chuàng)建很麻煩,那么我們可以把創(chuàng)建 Car 的復(fù)雜過程包裝起來:
public?class?MyCarFactoryBean?implements?FactoryBean<Car>{????private?String?make;? ????private?int?year?;????public?void?setMake(String?m){?this.make?=m?;?}????public?void?setYear(int?y){?this.year?=?y;?}????public?Car?getObject(){? ??????//?這里我們假設(shè)?Car?的實(shí)例化過程非常復(fù)雜,反正就不是幾行代碼可以寫完的那種 ??????CarBuilder?cb?=?CarBuilder.car();??????if(year!=0)?cb.setYear(this.year);??????if(StringUtils.hasText(this.make))?cb.setMake(?this.make?);? ??????return?cb.factory();? ????}????public?Class<Car>?getObjectType()?{?return?Car.class?;?}? ????public?boolean?isSingleton()?{?return?false;?} }
我們看看裝配的時(shí)候是怎么配置的:
<bean?class?=?"com.javadoop.MyCarFactoryBean"?id?=?"car"> ??<property?name?=?"make"?value?="Honda"/> ??<property?name?=?"year"?value?="1984"/></bean><bean?class?=?"com.javadoop.Person"?id?=?"josh"> ??<property?name?=?"car"?ref?=?"car"/></bean>
看到不一樣了嗎?id 為 “car” 的 bean 其實(shí)指定的是一個(gè) FactoryBean,不過配置的時(shí)候,我們直接讓配置 Person 的 Bean 直接依賴于這個(gè) FactoryBean 就可以了。中間的過程 Spring 已經(jīng)封裝好了。
說到這里,我們?cè)賮睃c(diǎn)干貨。我們知道,現(xiàn)在還用 xml 配置 Bean 依賴的越來越少了,更多時(shí)候,我們可能會(huì)采用 java config 的方式來配置,這里有什么不一樣呢?
@Configuration?public?class?CarConfiguration?{? ????@Bean? ????public?MyCarFactoryBean?carFactoryBean(){? ??????MyCarFactoryBean?cfb?=?new?MyCarFactoryBean(); ??????cfb.setMake("Honda"); ??????cfb.setYear(1984);??????return?cfb; ????}????@Bean ????public?Person?aPerson(){? ????Person?person?=?new?Person();??????//?注意這里的不同 ????person.setCar(carFactoryBean().getObject());????return?person;? ????}? }
這個(gè)時(shí)候,其實(shí)我們的思路也很簡單,把 MyCarFactoryBean 看成是一個(gè)簡單的 Bean 就可以了,不必理會(huì)什么 FactoryBean,它是不是 FactoryBean 和我們沒關(guān)系。
有以下四種方案:
<bean?id="exampleInitBean"?class="examples.ExampleBean"?init-method="init"/>
public?class?AnotherExampleBean?implements?InitializingBean?{????public?void?afterPropertiesSet()?{????????//?do?some?initialization?work ????} }
@Bean(initMethod?=?"init")public?Foo?foo()?{????return?new?Foo(); }
@PostConstructpublic?void?init()?{ }
<bean?id="exampleInitBean"?class="examples.ExampleBean"?destroy-method="cleanup"/>
public?class?AnotherExampleBean?implements?DisposableBean?{????public?void?destroy()?{????????//?do?some?destruction?work?(like?releasing?pooled?connections) ????} }
@Bean(destroyMethod?=?"cleanup")public?Bar?bar()?{????return?new?Bar(); }
@PreDestroypublic?void?cleanup()?{ }
既然文中說到了這個(gè),順便提一下好了。
最有用的場景就是,它用來將前端傳過來的參數(shù)和后端的 controller 方法上的參數(shù)進(jìn)行綁定的時(shí)候用。
像前端傳過來的字符串、整數(shù)要轉(zhuǎn)換為后端的 String、Integer 很容易,但是如果 controller 方法需要的是一個(gè)枚舉值,或者是 Date 這些非基礎(chǔ)類型(含基礎(chǔ)類型包裝類)值的時(shí)候,我們就可以考慮采用 ConversionService 來進(jìn)行轉(zhuǎn)換。
<bean?id="conversionService" ??class="org.springframework.context.support.ConversionServiceFactoryBean">??<property?name="converters"> ????<list> ??????<bean?class="com.javadoop.learning.utils.StringToEnumConverterFactory"/> ????</list> ??</property></bean>
ConversionService 接口很簡單,所以要自定義一個(gè) convert 的話也很簡單。
下面再說一個(gè)實(shí)現(xiàn)這種轉(zhuǎn)換很簡單的方式,那就是實(shí)現(xiàn) Converter 接口。
來看一個(gè)很簡單的例子,這樣比什么都管用。
public?class?StringToDateConverter?implements?Converter<String,?Date>?{????@Override ????public?Date?convert(String?source)?{????????try?{????????????return?DateUtils.parseDate(source,?"yyyy-MM-dd",?"yyyy-MM-dd?HH:mm:ss",?"yyyy-MM-dd?HH:mm",?"HH:mm:ss",?"HH:mm"); ????????}?catch?(ParseException?e)?{????????????return?null; ????????} ????} }
只要注冊(cè)這個(gè) Bean 就可以了。這樣,前端往后端傳的時(shí)間描述字符串就很容易綁定成 Date 類型了,不需要其他任何操作。
在初始化 Bean 的地方,我們說過了這個(gè):
RootBeanDefinition?bd?=?getMergedLocalBeanDefinition(beanName);
這里涉及到的就是?<bean parent="" />
?中的 parent 屬性,我們來看看 Spring 中是用這個(gè)來干什么的。
首先,我們要明白,這里的繼承和 java 語法中的繼承沒有任何關(guān)系,不過思路是相通的。child bean 會(huì)繼承 parent bean 的所有配置,也可以覆蓋一些配置,當(dāng)然也可以新增額外的配置。
Spring 中提供了繼承自 AbstractBeanDefinition 的?ChildBeanDefinition
?來表示 child bean。
看如下一個(gè)例子:
<bean?id="inheritedTestBean"?abstract="true"?class="org.springframework.beans.TestBean"> ????<property?name="name"?value="parent"/> ????<property?name="age"?value="1"/> </bean> <bean?id="inheritsWithDifferentClass"?class="org.springframework.beans.DerivedTestBean" ????????parent="inheritedTestBean"?init-method="initialize"> ????<property?name="name"?value="override"/> </bean>
parent bean 設(shè)置了?abstract="true"
?所以它不會(huì)被實(shí)例化,child bean 繼承了 parent bean 的兩個(gè)屬性,但是對(duì) name 屬性進(jìn)行了覆寫。
child bean 會(huì)繼承 scope、構(gòu)造器參數(shù)值、屬性值、init-method、destroy-method 等等。
當(dāng)然,我不是說 parent bean 中的 abstract = true 在這里是必須的,只是說如果加上了以后 Spring 在實(shí)例化 singleton beans 的時(shí)候會(huì)忽略這個(gè) bean。
比如下面這個(gè)極端 parent bean,它沒有指定 class,所以毫無疑問,這個(gè) bean 的作用就是用來充當(dāng)模板用的 parent bean,此處就必須加上 abstract = true。
<bean?id="inheritedTestBeanWithoutClass"?abstract="true"> ????<property?name="name"?value="parent"/> ????<property?name="age"?value="1"/></bean>
一般來說,我們的應(yīng)用中大多數(shù)的 Bean 都是 singleton 的。singleton 依賴 singleton,或者 prototype 依賴 prototype 都很好解決,直接設(shè)置屬性依賴就可以了。
但是,如果是 singleton 依賴 prototype 呢?這個(gè)時(shí)候不能用屬性依賴,因?yàn)槿绻脤傩砸蕾嚨脑?,我們每次其?shí)拿到的還是第一次初始化時(shí)候的 bean。
一種解決方案就是不要用屬性依賴,每次獲取依賴的 bean 的時(shí)候從 BeanFactory 中取。這個(gè)也是大家最常用的方式了吧。怎么取,我就不介紹了,大部分 Spring 項(xiàng)目大家都會(huì)定義那么個(gè)工具類的。
另一種解決方案就是這里要介紹的通過使用 Lookup method。
我們來看一下 Spring Reference 中提供的一個(gè)例子:
package?fiona.apple;//?no?more?Spring?imports!public?abstract?class?CommandManager?{????public?Object?process(Object?commandState)?{????????//?grab?a?new?instance?of?the?appropriate?Command?interface ????????Command?command?=?createCommand();????????//?set?the?state?on?the?(hopefully?brand?new)?Command?instance ????????command.setState(commandState);????????return?command.execute(); ????}????//?okay...?but?where?is?the?implementation?of?this?method? ????protected?abstract?Command?createCommand(); }
xml 配置?<lookup-method />
:
<!--?a?stateful?bean?deployed?as?a?prototype?(non-singleton)?--><bean?id="myCommand"?class="fiona.apple.AsyncCommand"?scope="prototype"> ????<!--?inject?dependencies?here?as?required?--></bean><!--?commandProcessor?uses?statefulCommandHelper?--><bean?id="commandManager"?class="fiona.apple.CommandManager"> ????<lookup-method?name="createCommand"?bean="myCommand"/></bean>
Spring 采用?CGLIB 生成字節(jié)碼的方式來生成一個(gè)子類。我們定義的類不能定義為 final class,抽象方法上也不能加 final。
lookup-method 上的配置也可以采用注解來完成,這樣就可以不用配置?<lookup-method />
?了,其他不變:
public?abstract?class?CommandManager?{????public?Object?process(Object?commandState)?{ ????????MyCommand?command?=?createCommand(); ????????command.setState(commandState);????????return?command.execute(); ????}????@Lookup("myCommand")????protected?abstract?Command?createCommand(); }
注意,既然用了注解,要配置注解掃描:
<context:component-scan base-package="com.javadoop" />
甚至,我們可以像下面這樣:
public?abstract?class?CommandManager?{????public?Object?process(Object?commandState)?{ ????????MyCommand?command?=?createCommand(); ????????command.setState(commandState);????????return?command.execute(); ????}????@Lookup ????protected?abstract?MyCommand?createCommand(); }
上面的返回值用了 MyCommand,當(dāng)然,如果 Command 只有一個(gè)實(shí)現(xiàn)類,那返回值也可以寫 Command。
記住它的功能,就是替換掉 bean 中的一些方法。
public?class?MyValueCalculator?{????public?String?computeValue(String?input)?{????????//?some?real?code... ????}????//?some?other?methods...}
方法覆寫,注意要實(shí)現(xiàn) MethodReplacer 接口:
public?class?ReplacementComputeValue?implements?org.springframework.beans.factory.support.MethodReplacer?{????public?Object?reimplement(Object?o,?Method?m,?Object[]?args)?throws?Throwable?{????????//?get?the?input?value,?work?with?it,?and?return?a?computed?result ????????String?input?=?(String)?args[0]; ????????...????????return?...; ????} }
配置也很簡單:
<bean?id="myValueCalculator"?class="x.y.z.MyValueCalculator"> ????<!--?定義?computeValue?這個(gè)方法要被替換掉?--> ????<replaced-method?name="computeValue"?replacer="replacementComputeValue"> ????????<arg-type>String</arg-type> ????</replaced-method></bean><bean?id="replacementComputeValue"?class="a.b.c.ReplacementComputeValue"/>
arg-type 明顯不是必須的,除非存在方法重載,這樣必須通過參數(shù)類型列表來判斷這里要覆蓋哪個(gè)方法。
應(yīng)該說 BeanPostProcessor 概念在 Spring 中也是比較重要的。我們看下接口定義:
public?interface?BeanPostProcessor?{???Object?postProcessBeforeInitialization(Object?bean,?String?beanName)?throws?BeansException;???Object?postProcessAfterInitialization(Object?bean,?String?beanName)?throws?BeansException; }
看這個(gè)接口中的兩個(gè)方法名字我們大體上可以猜測 bean 在初始化之前會(huì)執(zhí)行 postProcessBeforeInitialization 這個(gè)方法,初始化完成之后會(huì)執(zhí)行 postProcessAfterInitialization 這個(gè)方法。但是,這么理解是非常片面的。
首先,我們要明白,除了我們自己定義的 BeanPostProcessor 實(shí)現(xiàn)外,Spring 容器在啟動(dòng)時(shí)自動(dòng)給我們也加了幾個(gè)。如在獲取 BeanFactory 的 obtainFactory() 方法結(jié)束后的 prepareBeanFactory(factory),大家仔細(xì)看會(huì)發(fā)現(xiàn),Spring 往容器中添加了這兩個(gè) BeanPostProcessor:ApplicationContextAwareProcessor、ApplicationListenerDetector。鄭州好的不孕不育醫(yī)院有哪些:http://www.zzchyy110.com/
我們回到這個(gè)接口本身,讀者請(qǐng)看第一個(gè)方法,這個(gè)方法接受的第一個(gè)參數(shù)是 bean 實(shí)例,第二個(gè)參數(shù)是 bean 的名字,重點(diǎn)在返回值將會(huì)作為新的 bean 實(shí)例,所以,沒事的話這里不能隨便返回個(gè) null。
那意味著什么呢?我們很容易想到的就是,我們這里可以對(duì)一些我們想要修飾的 bean 實(shí)例做一些事情。但是對(duì)于 Spring 框架來說,它會(huì)決定是不是要在這個(gè)方法中返回 bean 實(shí)例的代理,這樣就有更大的想象空間了。
最后,我們說說如果我們自己定義一個(gè) bean 實(shí)現(xiàn) BeanPostProcessor 的話,它的執(zhí)行時(shí)機(jī)是什么時(shí)候?
如果仔細(xì)看了代碼分析的話,其實(shí)很容易知道了,在 bean 實(shí)例化完成、屬性注入完成之后,會(huì)執(zhí)行回調(diào)方法,具體請(qǐng)參見類 AbstractAutowireCapableBeanFactory#initBean 方法。
首先會(huì)回調(diào)幾個(gè)實(shí)現(xiàn)了 Aware 接口的 bean,然后就開始回調(diào) BeanPostProcessor 的 postProcessBeforeInitialization 方法,之后是回調(diào) init-method,然后再回調(diào) BeanPostProcessor 的 postProcessAfterInitialization 方法。http://www.chacha8.cn/detail/1132398250.html
按理說,總結(jié)應(yīng)該寫在附錄前面,我就不講究了。
在花了那么多時(shí)間后,這篇文章終于算是基本寫完了,大家在驚嘆 Spring 給我們做了那么多的事的時(shí)候,應(yīng)該透過現(xiàn)象看本質(zhì),去理解 Spring 寫得好的地方,去理解它的設(shè)計(jì)思想。
本文的缺陷在于對(duì) Spring 預(yù)初始化 singleton beans 的過程分析不夠,主要是代碼量真的比較大,分支旁路眾多。同時(shí),雖然附錄條目不少,但是龐大的 Spring 真的引出了很多的概念,希望日后有精力可以慢慢補(bǔ)充一些。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。