IOC的基礎(chǔ)?
下面我們從IOC/AOP開(kāi)始拟赊,它們是Spring平臺(tái)實(shí)現(xiàn)的核心部分匣吊;雖然盒件,我們一開(kāi)始大多只是在這個(gè)層面上刽严,做一些配置和外部特性的使用工作昂灵,但對(duì)這兩個(gè)核心模塊工作原理和運(yùn)作機(jī)制的理解,對(duì)深入理解Spring平臺(tái)舞萄,卻是至關(guān)重要的眨补;因?yàn)椋鼈兺瑫r(shí)也是Spring其他模塊實(shí)現(xiàn)的基礎(chǔ)倒脓。從Spring要做到的目標(biāo)撑螺,也就是從簡(jiǎn)化Java EE開(kāi)發(fā)的出發(fā)點(diǎn)來(lái)看,簡(jiǎn)單的來(lái)說(shuō)崎弃,它是通過(guò)對(duì)POJO開(kāi)發(fā)的支持甘晤,來(lái)具體實(shí)現(xiàn)的;具體的說(shuō)饲做,Spring通過(guò)為應(yīng)用開(kāi)發(fā)提供基于POJO的開(kāi)發(fā)模式线婚,把應(yīng)用開(kāi)發(fā)和復(fù)雜的Java EE服務(wù),實(shí)現(xiàn)解耦盆均,并通過(guò)提高單元測(cè)試的覆蓋率酌伊,從而有效的提高整個(gè)應(yīng)用的開(kāi)發(fā)質(zhì)量。這樣一來(lái),實(shí)際上居砖,就需要把為POJO提供支持的虹脯,各種Java EE服務(wù)支持抽象到應(yīng)用平臺(tái)中去,去封裝起來(lái)奏候;而這種封裝功能的實(shí)現(xiàn)循集,在Spring中,就是由IOC容器以及AOP來(lái)具體提供的蔗草,這兩個(gè)模塊咒彤,在很大程度上,體現(xiàn)了Spring作為應(yīng)用開(kāi)發(fā)平臺(tái)的核心價(jià)值咒精。它們的實(shí)現(xiàn)镶柱,是Rod.Johnson在他的另一本著作《Expert One-on-One J2EE Development without EJB》 中,所提到Without EJB設(shè)計(jì)思想的體現(xiàn)模叙;同時(shí)也深刻的體現(xiàn)了Spring背后的設(shè)計(jì)理念歇拆。?
從更深一點(diǎn)的技術(shù)層面上來(lái)看,因?yàn)镾pring是一個(gè)基于Java語(yǔ)言的應(yīng)用平臺(tái)范咨,如果我們能夠?qū)ava計(jì)算模型故觅,比如像JVM虛擬機(jī)實(shí)現(xiàn)技術(shù)的基本原理有一些了解,會(huì)讓我們對(duì)Spring實(shí)現(xiàn)的理解渠啊,更加的深入输吏,這些JVM虛擬機(jī)的特性使用,包括像反射機(jī)制替蛉,代理類贯溅,字節(jié)碼技術(shù)等等。它們都是在Spring實(shí)現(xiàn)中躲查,涉及到的一些Java計(jì)算環(huán)境的底層技術(shù)它浅;盡管對(duì)應(yīng)用開(kāi)發(fā)人員來(lái)說(shuō),可能不會(huì)直接去涉及這些JVM虛擬機(jī)底層實(shí)現(xiàn)的工作熙含,但是了解這些背景知識(shí),或多或少艇纺,對(duì)我們了解整個(gè)Spring平臺(tái)的應(yīng)用背景有很大的幫助怎静;打個(gè)比方來(lái)說(shuō),就像我們?cè)诖髮W(xué)中黔衡,學(xué)習(xí)的那些關(guān)于計(jì)算機(jī)組織和系統(tǒng)方面的基本知識(shí)蚓聘,比如像數(shù)字電路,計(jì)算機(jī)組成原理盟劫,匯編語(yǔ)言夜牡,操作系統(tǒng)等等這些基本課程的學(xué)習(xí)。雖然,坦率的來(lái)說(shuō)塘装,對(duì)我們這些大多數(shù)課程的學(xué)習(xí)者急迂,在以后的工作中,可能并沒(méi)有太多的機(jī)會(huì)蹦肴,直接從事這么如此底層的技術(shù)開(kāi)發(fā)工作僚碎;但具備這些知識(shí)背景,為我們深入理解基于這些基礎(chǔ)技術(shù)構(gòu)架起來(lái)的應(yīng)用系統(tǒng)阴幌,毫無(wú)疑問(wèn)勺阐,是不可缺少的。隨著JVM虛擬機(jī)技術(shù)的發(fā)展矛双,可以設(shè)想到的是渊抽,更多虛擬機(jī)級(jí)別的基本特性,將會(huì)持續(xù)的被應(yīng)用平臺(tái)開(kāi)發(fā)者所關(guān)注和采用议忽,這也是我們?cè)趯W(xué)習(xí)平臺(tái)實(shí)現(xiàn)的過(guò)程中懒闷,非常值得注意的一點(diǎn),因?yàn)檫@些底層技術(shù)實(shí)現(xiàn)徙瓶,毫無(wú)疑問(wèn)毛雇,會(huì)對(duì)Spring應(yīng)用平臺(tái)的開(kāi)發(fā)路線,產(chǎn)品策略產(chǎn)生重大的影響侦镇。同時(shí)灵疮,在使用Spring作為應(yīng)用平臺(tái)的時(shí)候,如果需要更深層次的開(kāi)發(fā)和性能調(diào)優(yōu)壳繁,這些底層的知識(shí)震捣,也是我們知識(shí)庫(kù)中不可缺少的部分。有了這些底層知識(shí)闹炉,理解整個(gè)系統(tǒng)蒿赢,想來(lái)就應(yīng)該障礙不大了。?
IOC的一點(diǎn)認(rèn)識(shí)?
對(duì)Spring IOC的理解離不開(kāi)對(duì)依賴反轉(zhuǎn)模式的理解渣触,我們知道羡棵,關(guān)于如何反轉(zhuǎn)對(duì)依賴的控制,把控制權(quán)從具體業(yè)務(wù)對(duì)象手中轉(zhuǎn)交到平臺(tái)或者框架中嗅钻,是解決面向?qū)ο笙到y(tǒng)設(shè)計(jì)復(fù)雜性和提高面向?qū)ο笙到y(tǒng)可測(cè)試性的一個(gè)有效的解決方案皂冰。這個(gè)問(wèn)題觸發(fā)了IoC設(shè)計(jì)模式的發(fā)展,是IoC容器要解決的核心問(wèn)題养篓。同時(shí)秃流,也是產(chǎn)品化的IoC容器出現(xiàn)的推動(dòng)力。而我覺(jué)得Spring的IoC容器柳弄,就是一個(gè)開(kāi)源的實(shí)現(xiàn)依賴反轉(zhuǎn)模式的產(chǎn)品舶胀。?
那具體什么是IoC容器呢?它在Spring框架中到底長(zhǎng)什么樣?說(shuō)了這么多嚣伐,其實(shí)對(duì)IoC容器的使用者來(lái)說(shuō)糖赔,我們常常接觸到的BeanFactory和ApplicationContext都可以看成是容器的具體表現(xiàn)形式。這些就是IoC容器纤控,或者說(shuō)在Spring中提IoC容器挂捻,從實(shí)現(xiàn)來(lái)說(shuō),指的是一個(gè)容器系列船万。這也就是說(shuō)刻撒,我們通常所說(shuō)的IoC容器,如果深入到Spring的實(shí)現(xiàn)去看耿导,會(huì)發(fā)現(xiàn)IoC容器實(shí)際上代表著一系列功能各異的容器產(chǎn)品声怔。只是容器的功能有大有小,有各自的特點(diǎn)舱呻。打個(gè)比方來(lái)說(shuō)醋火,就像是百貨商店里出售的商品,我們舉水桶為例子箱吕,在商店中出售的水桶有大有薪娌怠;制作材料也各不相同茬高,有金屬的兆旬,有塑料的等等,總之是各式各樣怎栽,但只要能裝水丽猬,具備水桶的基本特性,那就可以作為水桶來(lái)出售來(lái)讓用戶使用熏瞄。這在Spring中也是一樣脚祟,它有各式各樣的IoC容器的實(shí)現(xiàn)供用戶選擇和使用;使用什么樣的容器完全取決于用戶的需要强饮,但在使用之前如果能夠了解容器的基本情況由桌,那會(huì)對(duì)容器的使用是非常有幫助的;就像我們?cè)谫?gòu)買(mǎi)商品時(shí)進(jìn)行的對(duì)商品的考察和挑選那樣邮丰。?
我們從最基本的XmlBeanFactory看起行您,它是容器系列的最底層實(shí)現(xiàn),這個(gè)容器的實(shí)現(xiàn)與我們?cè)赟pring應(yīng)用中用到的那些上下文相比柠座,有一個(gè)非常明顯的特點(diǎn)邑雅,它只提供了最基本的IoC容器的功能片橡。從它的名字中可以看出妈经,這個(gè)IoC容器可以讀取以XML形式定義的BeanDefinition。理解這一點(diǎn)有助于我們理解ApplicationContext與基本的BeanFactory之間的區(qū)別和聯(lián)系。我們可以認(rèn)為直接的BeanFactory實(shí)現(xiàn)是IoC容器的基本形式吹泡,而各種ApplicationContext的實(shí)現(xiàn)是IoC容器的高級(jí)表現(xiàn)形式骤星。?
仔細(xì)閱讀XmlBeanFactory的源碼,在一開(kāi)始的注釋里面已經(jīng)對(duì) XmlBeanFactory的功能做了簡(jiǎn)要的說(shuō)明爆哑,從代碼的注釋還可以看到洞难,這是Rod Johnson在2001年就寫(xiě)下的代碼,可見(jiàn)這個(gè)類應(yīng)該是Spring的元老類了揭朝。它是繼承DefaultListableBeanFactory這個(gè)類的队贱,這個(gè)DefaultListableBeanFactory就是一個(gè)很值得注意的容器!?
Java代碼?
public?class?XmlBeanFactory?extends?DefaultListableBeanFactory?{??
private?final?XmlBeanDefinitionReader?reader?=?new?XmlBeanDefinitionReader(this);??
public?XmlBeanFactory(Resource?resource)?throws?BeansException?{??
this(resource,?null);??
????}??
public?XmlBeanFactory(Resource?resource,?BeanFactory?parentBeanFactory)?throws?BeansException?{??
super(parentBeanFactory);??
this.reader.loadBeanDefinitions(resource);??
????}??
}??
XmlBeanFactory的功能是建立在DefaultListableBeanFactory這個(gè)基本容器的基礎(chǔ)上的潭袱,在這個(gè)基本容器的基礎(chǔ)上實(shí)現(xiàn)了其他諸如XML讀取的附加功能柱嫌。對(duì)于這些功能的實(shí)現(xiàn)原理,看一看XmlBeanFactory的代碼實(shí)現(xiàn)就能很容易地理解屯换。在如下的代碼中可以看到编丘,在XmlBeanFactory構(gòu)造方法中需要得到Resource對(duì)象。對(duì)XmlBeanDefinitionReader對(duì)象的初始化彤悔,以及使用這個(gè)這個(gè)對(duì)象來(lái)完成loadBeanDefinitions的調(diào)用嘉抓,就是這個(gè)調(diào)用啟動(dòng)了從Resource中載入BeanDefinitions的過(guò)程,這個(gè)loadBeanDefinitions同時(shí)也是IoC容器初始化的重要組成部分晕窑。?
簡(jiǎn)單來(lái)說(shuō)抑片,IoC容器的初始化包括BeanDefinition的Resouce定位、載入和注冊(cè)這三個(gè)基本的過(guò)程幕屹。我覺(jué)得重點(diǎn)是在載入和對(duì)BeanDefinition做解析的這個(gè)過(guò)程蓝丙。可以從DefaultListableBeanFactory來(lái)入手看看IoC容器是怎樣完成BeanDefinition載入的望拖。在refresh調(diào)用完成以后渺尘,可以看到loadDefinition的調(diào)用:?
Java代碼?
public?abstract?class?AbstractXmlApplicationContext?extends?AbstractRefreshableConfigApplicationContext?{??
public?AbstractXmlApplicationContext()?{??
????}??
public?AbstractXmlApplicationContext(ApplicationContext?parent)?{??
super(parent);??
????}??
//這里是實(shí)現(xiàn)loadBeanDefinitions的地方??
protected?void?loadBeanDefinitions(DefaultListableBeanFactory?beanFactory)?throws?IOException?{??
//?Create?a?new?XmlBeanDefinitionReader?for?the?given?BeanFactory.??
//?創(chuàng)建?XmlBeanDefinitionReader,并通過(guò)回調(diào)設(shè)置到?BeanFactory中去说敏,創(chuàng)建BeanFactory的使用的也是?DefaultListableBeanFactory鸥跟。??
XmlBeanDefinitionReader?beanDefinitionReader?=new?XmlBeanDefinitionReader(beanFactory);??
//?Configure?the?bean?definition?reader?with?this?context's??
//?resource?loading?environment.??
//?這里設(shè)置?XmlBeanDefinitionReader,?為XmlBeanDefinitionReader?配置ResourceLoader盔沫,因?yàn)镈efaultResourceLoader是父類医咨,所以this可以直接被使用??
beanDefinitionReader.setResourceLoader(this);??
beanDefinitionReader.setEntityResolver(new?ResourceEntityResolver(this));??
//?Allow?a?subclass?to?provide?custom?initialization?of?the?reader,??
//?then?proceed?with?actually?loading?the?bean?definitions.??
//?這是啟動(dòng)Bean定義信息載入的過(guò)程??
????????initBeanDefinitionReader(beanDefinitionReader);??
????????loadBeanDefinitions(beanDefinitionReader);??
????}??
protected?void?initBeanDefinitionReader(XmlBeanDefinitionReader?beanDefinitionReader)?{??
????}??
這里使用 XmlBeanDefinitionReader來(lái)載入BeanDefinition到容器中,如以下代碼清單所示:?
Java代碼?
????//這里是調(diào)用的入口架诞。??
public?int?loadBeanDefinitions(Resource?resource)?throws?BeanDefinitionStoreException?{??
return?loadBeanDefinitions(new?EncodedResource(resource));??
????}??
//這里是載入XML形式的BeanDefinition的地方拟淮。??
public?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());??
????????}??
Set?currentResources?=this.resourcesCurrentlyBeingLoaded.get();??
if?(currentResources?==?null)?{??
currentResources?=new?HashSet(4);??
this.resourcesCurrentlyBeingLoaded.set(currentResources);??
????????}??
if?(!currentResources.add(encodedResource))?{??
throw?new?BeanDefinitionStoreException(??
"Detected?recursive?loading?of?"?+?encodedResource?+?"?-?check?your?import?definitions!");??
????????}??
//這里得到XML文件,并得到IO的InputSource準(zhǔn)備進(jìn)行讀取谴忧。??
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.set(null);??
????????????}??
????????}??
????}??
//具體的讀取過(guò)程可以在doLoadBeanDefinitions方法中找到:??
//這是從特定的XML文件中實(shí)際載入BeanDefinition的地方??
protected?int?doLoadBeanDefinitions(InputSource?inputSource,?Resource?resource)??
throws?BeanDefinitionStoreException?{??
try?{??
int?validationMode?=?getValidationModeForResource(resource);??
//這里取得XML文件的Document對(duì)象很泊,這個(gè)解析過(guò)程是由?documentLoader完成的角虫,這個(gè)documentLoader是DefaultDocumentLoader,在定義documentLoader的地方創(chuàng)建??
Document?doc?=this.documentLoader.loadDocument(??
inputSource,?getEntityResolver(),this.errorHandler,?validationMode,?isNamespaceAware());??
//這里啟動(dòng)的是對(duì)BeanDefinition解析的詳細(xì)過(guò)程,這個(gè)解析會(huì)使用到Spring的Bean配置規(guī)則委造,是我們下面需要詳細(xì)關(guān)注的地方戳鹅。??
return?registerBeanDefinitions(doc,?resource);??
????????}??
catch?(BeanDefinitionStoreException?ex)?{??
throw?ex;??
????????}??
catch?(SAXParseException?ex)?{??
throw?new?XmlBeanDefinitionStoreException(resource.getDescription(),??
"Line?"?+?ex.getLineNumber()?+?"?in?XML?document?from?"?+?resource?+?"?is?invalid",?ex);??
????????}??
catch?(SAXException?ex)?{??
throw?new?XmlBeanDefinitionStoreException(resource.getDescription(),??
"XML?document?from?"?+?resource?+?"?is?invalid",?ex);??
????????}??
catch?(ParserConfigurationException?ex)?{??
throw?new?BeanDefinitionStoreException(resource.getDescription(),??
"Parser?configuration?exception?parsing?XML?from?"?+?resource,?ex);??
????????}??
catch?(IOException?ex)?{??
throw?new?BeanDefinitionStoreException(resource.getDescription(),??
"IOException?parsing?XML?document?from?"?+?resource,?ex);??
????????}??
catch?(Throwable?ex)?{??
throw?new?BeanDefinitionStoreException(resource.getDescription(),??
"Unexpected?exception?parsing?XML?document?from?"?+?resource,?ex);??
????????}??
????}??
關(guān)于具體的Spring BeanDefinition的解析,是在BeanDefinitionParserDelegate中完成的昏兆。這個(gè)類里包含了各種Spring Bean定義規(guī)則的處理枫虏,感興趣的同學(xué)可以仔細(xì)研究。我們舉一個(gè)例子來(lái)分析這個(gè)處理過(guò)程爬虱,比如我們最熟悉的對(duì)Bean元素的處理是怎樣完成的隶债,也就是我們?cè)赬ML定義文件中出現(xiàn)的這個(gè)最常見(jiàn)的元素信息是怎樣被處理的。在這里跑筝,我們會(huì)看到那些熟悉的BeanDefinition定義的處理燃异,比如id、name继蜡、aliase等屬性元素回俐。把這些元素的值從XML文件相應(yīng)的元素的屬性中讀取出來(lái)以后,會(huì)被設(shè)置到生成的BeanDefinitionHolder中去稀并。這些屬性的解析還是比較簡(jiǎn)單的仅颇。對(duì)于其他元素配置的解析,比如各種Bean的屬性配置碘举,通過(guò)一個(gè)較為復(fù)雜的解析過(guò)程忘瓦,這個(gè)過(guò)程是由parseBeanDefinitionElement來(lái)完成的。解析完成以后引颈,會(huì)把解析結(jié)果放到BeanDefinition對(duì)象中并設(shè)置到BeanDefinitionHolder中去耕皮,如以下清單所示:?
Java代碼?
public?BeanDefinitionHolder?parseBeanDefinitionElement(Element?ele,?BeanDefinition?containingBean)?{??
//這里取得在元素中定義的id、name和aliase屬性的值??
????????String?id?=?ele.getAttribute(ID_ATTRIBUTE);??
????????String?nameAttr?=?ele.getAttribute(NAME_ATTRIBUTE);??
List?aliases?=new?ArrayList();??
if?(StringUtils.hasLength(nameAttr))?{??
????????????String[]?nameArr?=?StringUtils.tokenizeToStringArray(nameAttr,?BEAN_NAME_DELIMITERS);??
????????????aliases.addAll(Arrays.asList(nameArr));??
????????}??
????????String?beanName?=?id;??
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);??
????????}??
//這個(gè)方法會(huì)引發(fā)對(duì)bean元素的詳細(xì)解析??
AbstractBeanDefinition?beanDefinition?=?parseBeanDefinitionElement(ele,?beanName,?containingBean);??
if?(beanDefinition?!=?null)?{??
if?(!StringUtils.hasText(beanName))?{??
try?{??
if?(containingBean?!=?null)?{??
????????????????????????beanName?=?BeanDefinitionReaderUtils.generateBeanName(??
beanDefinition,this.readerContext.getRegistry(),?true);??
????????????????????}??
else?{??
beanName?=this.readerContext.generateBeanName(beanDefinition);??
//?Register?an?alias?for?the?plain?bean?class?name,?if?still?possible,??
//?if?the?generator?returned?the?class?name?plus?a?suffix.??
//?This?is?expected?for?Spring?1.2/2.0?backwards?compatibility.??
????????????????????????String?beanClassName?=?beanDefinition.getBeanClassName();??
if?(beanClassName?!=?null?&&??
????????????????????????????????beanName.startsWith(beanClassName)?&&?beanName.length()?>?beanClassName.length()?&&??
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName))?{??
????????????????????????????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);??
return?new?BeanDefinitionHolder(beanDefinition,?beanName,?aliasesArray);??
????????}??
return?null;??
????}??
在具體生成BeanDefinition以后蝙场。我們舉一個(gè)對(duì)property進(jìn)行解析的例子來(lái)完成對(duì)整個(gè)BeanDefinition載入過(guò)程的分析凌停,還是在類BeanDefinitionParserDelegate的代碼中,它對(duì)BeanDefinition中的定義一層一層地進(jìn)行解析售滤,比如從屬性元素集合到具體的每一個(gè)屬性元素罚拟,然后才是對(duì)具體的屬性值的處理。根據(jù)解析結(jié)果完箩,對(duì)這些屬性值的處理會(huì)封裝成PropertyValue對(duì)象并設(shè)置到BeanDefinition對(duì)象中去赐俗,如以下代碼清單所示。?
Java代碼?
/**
?*?這里對(duì)指定bean元素的property子元素集合進(jìn)行解析弊知。
?*/??
public?void?parsePropertyElements(Element?beanEle,?BeanDefinition?bd)?{??
//遍歷所有bean元素下定義的property元素??
????NodeList?nl?=?beanEle.getChildNodes();??
for?(int?i?=?0;?i?<?nl.getLength();?i++)?{??
????????Node?node?=?nl.item(i);??
if?(node?instanceof?Element?&&?DomUtils.nodeNameEquals(node,?PROPERTY_ELEMENT))?{??
//在判斷是property元素后對(duì)該property元素進(jìn)行解析的過(guò)程??
????????????parsePropertyElement((Element)?node,?bd);??
????????}??
????}??
}??
public?void?parsePropertyElement(Element?ele,?BeanDefinition?bd)?{??
//這里取得property的名字??
????String?propertyName?=?ele.getAttribute(NAME_ATTRIBUTE);??
if?(!StringUtils.hasLength(propertyName))?{??
error("Tag?'property'?must?have?a?'name'?attribute",?ele);??
return;??
????}??
this.parseState.push(new?PropertyEntry(propertyName));??
try?{??
//如果同一個(gè)bean中已經(jīng)有同名的存在阻逮,則不進(jìn)行解析,直接返回秩彤。也就是說(shuō)叔扼,如果在同一個(gè)bean中有同名的property設(shè)置皆尔,那么起作用的只是第一個(gè)。??
if?(bd.getPropertyValues().contains(propertyName))?{??
error("Multiple?'property'?definitions?for?property?'"?+?propertyName?+?"'",?ele);??
return;??
????????}??
//這里是解析property值的地方币励,返回的對(duì)象對(duì)應(yīng)對(duì)Bean定義的property屬性設(shè)置的解析結(jié)果,這個(gè)解析結(jié)果會(huì)封裝到PropertyValue對(duì)象中珊拼,然后設(shè)置到BeanDefinitionHolder中去食呻。??
????????Object?val?=?parsePropertyValue(ele,?bd,?propertyName);??
PropertyValue?pv?=new?PropertyValue(propertyName,?val);??
????????parseMetaElements(ele,?pv);??
????????pv.setSource(extractSource(ele));??
????????bd.getPropertyValues().addPropertyValue(pv);??
????}??
finally?{??
this.parseState.pop();??
????}??
}??
/**
?*?這里取得property元素的值,也許是一個(gè)list或其他澎现。
?*/??
public?Object?parsePropertyValue(Element?ele,?BeanDefinition?bd,?String?propertyName)?{??
String?elementName?=?(propertyName?!=null)????
"?element?for?property?'"?+?propertyName?+?"'"?:??
"?element";??
//?Should?only?have?one?child?element:?ref,?value,?list,?etc.??
????NodeList?nl?=?ele.getChildNodes();??
Element?subElement?=null;??
for?(int?i?=?0;?i?<?nl.getLength();?i++)?{??
????????Node?node?=?nl.item(i);??
if?(node?instanceof?Element?&&?!DomUtils.nodeNameEquals(node,?DESCRIPTION_ELEMENT)?&&??
????????????????!DomUtils.nodeNameEquals(node,?META_ELEMENT))?{??
//?Child?element?is?what?we're?looking?for.??
if?(subElement?!=?null)?{??
error(elementName?+"?must?not?contain?more?than?one?sub-element",?ele);??
????????????}??
else?{??
????????????????subElement?=?(Element)?node;??
????????????}??
????????}??
????}??
//這里判斷property的屬性仅胞,是ref還是value,不允許同時(shí)是ref和value。??
boolean?hasRefAttribute?=?ele.hasAttribute(REF_ATTRIBUTE);??
boolean?hasValueAttribute?=?ele.hasAttribute(VALUE_ATTRIBUTE);??
if?((hasRefAttribute?&&?hasValueAttribute)?||??
((hasRefAttribute?||?hasValueAttribute)?&&?subElement?!=null))?{??
????????error(elementName?+??
"?is?only?allowed?to?contain?either?'ref'?attribute?OR?'value'?attribute?OR?sub-element",?ele);??
????}??
//如果是ref剑辫,創(chuàng)建一個(gè)ref的數(shù)據(jù)對(duì)象RuntimeBeanReference,這個(gè)對(duì)象封裝了ref的信息干旧。??
if?(hasRefAttribute)?{??
????????String?refName?=?ele.getAttribute(REF_ATTRIBUTE);??
if?(!StringUtils.hasText(refName))?{??
error(elementName?+"?contains?empty?'ref'?attribute",?ele);??
????????}??
RuntimeBeanReference?ref?=new?RuntimeBeanReference(refName);??
????????ref.setSource(extractSource(ele));??
return?ref;??
}//如果是value,創(chuàng)建一個(gè)value的數(shù)據(jù)對(duì)象TypedStringValue?,這個(gè)對(duì)象封裝了value的信息妹蔽。??
else?if?(hasValueAttribute)?{??
TypedStringValue?valueHolder?=new?TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));??
????????valueHolder.setSource(extractSource(ele));??
return?valueHolder;??
}//如果還有子元素椎眯,觸發(fā)對(duì)子元素的解析??
else?if?(subElement?!=?null)?{??
return?parsePropertySubElement(subElement,?bd);??
????}??
else?{??
//?Neither?child?element?nor?"ref"?or?"value"?attribute?found.??
error(elementName?+"?must?specify?a?ref?or?value",?ele);??
return?null;??
????}??
}??
比如,再往下看胳岂,我們看到像List這樣的屬性配置是怎樣被解析的编整,依然在BeanDefinitionParserDelegate中:返回的是一個(gè)List對(duì)象,這個(gè)List是Spring定義的ManagedList乳丰,作為封裝List這類配置定義的數(shù)據(jù)封裝掌测,如以下代碼清單所示。?
Java代碼?
public?List?parseListElement(Element?collectionEle,?BeanDefinition?bd)?{??
????String?defaultElementType?=?collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE);??
????NodeList?nl?=?collectionEle.getChildNodes();??
ManagedList?target?=new?ManagedList(nl.getLength());??
????target.setSource(extractSource(collectionEle));??
????target.setElementTypeName(defaultElementType);??
????target.setMergeEnabled(parseMergeAttribute(collectionEle));??
//具體的List元素的解析過(guò)程产园。??
????parseCollectionElements(nl,?target,?bd,?defaultElementType);??
return?target;??
}??
protected?void?parseCollectionElements(??
????????NodeList?elementNodes,?Collection?target,?BeanDefinition?bd,?String?defaultElementType)?{??
//遍歷所有的元素節(jié)點(diǎn)汞斧,并判斷其類型是否為Element。??
for?(int?i?=?0;?i?<?elementNodes.getLength();?i++)?{??
????????Node?node?=?elementNodes.item(i);??
if?(node?instanceof?Element?&&?!DomUtils.nodeNameEquals(node,?DESCRIPTION_ELEMENT))?{??
//加入到target中去什燕,target是一個(gè)ManagedList粘勒,同時(shí)觸發(fā)對(duì)下一層子元素的解析過(guò)程,這是一個(gè)遞歸的調(diào)用屎即。??
????????????target.add(parsePropertySubElement((Element)?node,?bd,?defaultElementType));??
????????}??
????}??
}??
經(jīng)過(guò)這樣一層一層的解析仲义,我們?cè)赬ML文件中定義的BeanDefinition就被整個(gè)給載入到了IoC容器中,并在容器中建立了數(shù)據(jù)映射剑勾。在IoC容器中建立了對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu)埃撵,或者說(shuō)可以看成是POJO對(duì)象在IoC容器中的映像,這些數(shù)據(jù)結(jié)構(gòu)可以以AbstractBeanDefinition為入口虽另,讓IoC容器執(zhí)行索引暂刘、查詢和操作。?
在我的感覺(jué)中捂刺,對(duì)核心數(shù)據(jù)結(jié)構(gòu)的定義和處理應(yīng)該可以看成是一個(gè)軟件的核心部分了谣拣。所以募寨,這里的BeanDefinition的載入可以說(shuō)是IoC容器的核心,如果說(shuō)IoC容器是Spring的核心森缠,那么這些BeanDefinition就是Spring的核心的核心了拔鹰!?
呵呵,這部分代碼數(shù)量不小贵涵,但如果掌握這條主線列肢,其他都可以舉一反三吧,就像我們掌握了操作系統(tǒng)啟動(dòng)的過(guò)程宾茂,以及在操作系統(tǒng)設(shè)計(jì)中的核心數(shù)據(jù)結(jié)構(gòu)像進(jìn)程數(shù)據(jù)結(jié)構(gòu)瓷马,文件系統(tǒng)數(shù)據(jù)結(jié)構(gòu),網(wǎng)絡(luò)協(xié)議數(shù)據(jù)結(jié)構(gòu)的設(shè)計(jì)和處理一樣跨晴,對(duì)整個(gè)系統(tǒng)的設(shè)計(jì)原理欧聘,包括移植,驅(qū)動(dòng)開(kāi)發(fā)和應(yīng)用開(kāi)發(fā)端盆,是非常有幫助的怀骤!?