日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

BeanDefinition的载入和解析

發(fā)布時(shí)間:2025/3/16 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 BeanDefinition的载入和解析 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

概念

第二個(gè)過(guò)程是BeanDefinition的載入。這個(gè)載入過(guò)程是把用戶定義好的Bean表示成IoC容器內(nèi)部的數(shù)據(jù)結(jié)構(gòu),而這個(gè)容器內(nèi)部的數(shù)據(jù)結(jié)構(gòu)就是BeanDefinition。具體來(lái)說(shuō),這個(gè)BeanDefinition實(shí)際上就是POJO對(duì)象在IoC容器中的抽象,通過(guò)這個(gè)BeanDefinition定義的數(shù)據(jù)結(jié)構(gòu),使IoC容器能夠方便地對(duì)POJO對(duì)象也就是Bean進(jìn)行管理。IoC容器對(duì)Bean的管理和依賴注入功能的實(shí)現(xiàn),就是通過(guò)對(duì)持有的BeanDefinition進(jìn)行各種相關(guān)操作完成的。


分析過(guò)程

  • 整個(gè)載入和解析過(guò)程也是從refresh()啟動(dòng)的,該方法在FileSystemXmlApplicationContext的基類(lèi)AbstractApplic-ationContext中實(shí)現(xiàn),它詳細(xì)的描述了整個(gè)ApplicationContext的初始化過(guò)程,比如BeanFactory的更新,Mess-ageSource和PostProcessor的注冊(cè),等等。這里看起來(lái)更像是對(duì)ApplicationContext進(jìn)行初始化的模板或執(zhí)行提綱,這個(gè)執(zhí)行過(guò)程為Bean的生命周期管理提供了條件。


public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.prepareRefresh();// Tell the subclass to refresh the internal bean factory.//這里是在子類(lèi)中啟動(dòng)refreshBeanFactory()的地方,也就是創(chuàng)建實(shí)際BeanFactory的方法入口ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.//設(shè)置BeanFactory的后置處理postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.//調(diào)用BeanFactory的后處理器.這些后處理器是在Bean定義中向容器注冊(cè)的invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.//注冊(cè)Bean的后處理器,在Bean創(chuàng)建過(guò)程中調(diào)用。registerBeanPostProcessors(beanFactory);// Initialize message source for this context.、//對(duì)上下文中的消息源進(jìn)行初始化initMessageSource();// Initialize event multicaster for this context.//初始化上下文中的事件機(jī)制initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.//初始化其他的特殊BeanonRefresh();// Check for listener beans and register them.//檢查監(jiān)聽(tīng)Bean并且將這些Bean向容器注冊(cè)registerListeners();// Instantiate all remaining (non-lazy-init) singletons.//實(shí)例化所有的(non-lazy-init)單件finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.//發(fā)布容器事件.結(jié)束Refresh過(guò)程finishRefresh();}catch (BeansException ex) {// Destroy already created singletons to avoid dangling resources.//為防止Bean資源占用,在異常處理中,銷(xiāo)毀已經(jīng)在前面過(guò)程中生成的單間BeandestroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}}}


  • 之后就進(jìn)行資源定位過(guò)程,定位完成后就開(kāi)始載入過(guò)程(見(jiàn)圖一),因?yàn)橹皠?chuàng)建好DefaultListBeanFactory后,將其“綁定”給XmlBeanDefinitionReader,由XmlBeanDefinitionReader繼續(xù)后續(xù)的定位和載入(圖二),所以這里的載入過(guò)程也由XmlBeanDefinitionReader來(lái)完成。需要注意的是,因?yàn)檫@里我們使用XML方式定義Bean,所以使用XmlBeanDefinitionReader來(lái)處理,如果使用了其他定義方式,就需要使用其他種類(lèi)的BeanDefinitionReader來(lái)完成載入工作。



  • 這里調(diào)用的是loadBeanDefinitions(Resource res)方法,但這個(gè)方法在AbstractBeanDefinitionReader類(lèi)里是沒(méi)有實(shí)現(xiàn)的,它是一個(gè)接口方法,具體的實(shí)現(xiàn)在XmlBeanDefinitionReader中。在讀取器中,需要得到代表XML文件的Resource,因?yàn)檫@個(gè)Resource對(duì)象封裝了對(duì)XML文件的I/O操作,所以讀取器可以在打開(kāi)I/O流后得到 XML的文件對(duì)象。有了這個(gè)文件對(duì)象以后,就可以按照Spring的Bean定義規(guī)則來(lái)對(duì)這個(gè)XML的文檔樹(shù)進(jìn)行解析。


//父類(lèi)AbstractBeanDefinitionReader遍歷調(diào)用loadBeanDefinitions(resource) public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {Assert.notNull(resources, "Resource array must not be null");int counter = 0;for (Resource resource : resources) {counter += loadBeanDefinitions(resource);}return counter; }//子類(lèi)XmlBeanDefinitionReader對(duì)loadBeanDefinitions(Resource resource)的具體實(shí)現(xiàn) public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {return loadBeanDefinitions(new EncodedResource(resource)); }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<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!");}//這里得到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());}//具體的讀取過(guò)程在doLoadBeanDefinitions中,是從特定的XML文件中實(shí)際載入的地方。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();}} }//子類(lèi)XmlBeanDefinitionReader的doLoadBeanDefinitions方法 protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)throws BeanDefinitionStoreException {try {int validationMode = getValidationModeForResource(resource);//這里取得XML的Document對(duì)象,如何獲得可詳細(xì)看源碼。Document doc = this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());//這里啟動(dòng)對(duì)BeanDefinition解析的詳細(xì)過(guò)程,這個(gè)解析會(huì)使用到Spring的Bean配置規(guī)則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);}}//子類(lèi)XmlBeanDefinitionReader的registerBeanDefinitions方法 public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {//得到BeanDefinitionDocumentReader來(lái)對(duì)XML進(jìn)行解析BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();documentReader.setEnvironment(this.getEnvironment());int countBefore = getRegistry().getBeanDefinitionCount();//具體的解析過(guò)程在BeanDefinitionDocumentReader的registerBeanDefinitions中完成。//createReaderContext(resource)返回一個(gè)ReaderContext對(duì)象,里面封裝了XmlBeanDefinitionReader等組件。documentReader.registerBeanDefinitions(doc, createReaderContext(resource));return getRegistry().getBeanDefinitionCount() - countBefore;}


  • BeanDefinition的載入分成兩部分,首先通過(guò)調(diào)用XML的解析器得到document對(duì)象,但這些document對(duì)象并沒(méi)有按照Spring的Bean規(guī)則進(jìn)行解析。在完成通用的XML解析以后,才是按照Spring的Bean規(guī)則進(jìn)行解析的地方,這個(gè)按照Spring的Bean規(guī)則進(jìn)行解析的過(guò)程是在documentReader中實(shí)現(xiàn)的。這里使用的documentReader是默認(rèn)設(shè)置好的DefaultBeanDefinitionDocumentReader。然后就完成BeanDefinition的處理,處理的結(jié)果由Bean-DefinitionHolder對(duì)象來(lái)持有。這個(gè)BeanDefinitionHolder除了持有BeanDefinition對(duì)象外,還持有其他與Bean-Definition的使用相關(guān)的信息,比如Bean的名字、別名集合等。這個(gè)BeanDefinitionHolder的生成是通過(guò)對(duì)Docu-ment文檔樹(shù)的內(nèi)容進(jìn)行解析來(lái)完成的,可以看到這個(gè)解析過(guò)程是由BeanDefinitionParserDelegate來(lái)實(shí)現(xiàn)(具體在processBeanDefinition方法中實(shí)現(xiàn))的,同時(shí)這個(gè)解析是與Spring對(duì)BeanDefinition的配置規(guī)則緊密相關(guān)的。具體的實(shí)現(xiàn)原理如下代碼:


//DefaultBeanDefinitionDocumentReader中的registerBeanDefinitions方法 public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {//將封裝了XmlBeanDefinitionReader等組件的XmlReaderContext傳給DefaultBeanDefinitionDocumentReader,方便后續(xù)回調(diào)。this.readerContext = readerContext;logger.debug("Loading bean definitions");Element root = doc.getDocumentElement();doRegisterBeanDefinitions(root); }//DefaultBeanDefinitionDocumentReader中的doRegisterBeanDefinitions方法 protected void doRegisterBeanDefinitions(Element root) {String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);if (StringUtils.hasText(profileSpec)) {Assert.state(this.environment != null, "environment property must not be null");String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);if (!this.environment.acceptsProfiles(specifiedProfiles)) {return;}}// any nested <beans> elements will cause recursion in this method. In// order to propagate and preserve <beans> default-* attributes correctly,// keep track of the current (parent) delegate, which may be null. Create// the new (child) delegate with a reference to the parent for fallback purposes,// then ultimately reset this.delegate back to its original (parent) reference.// this behavior emulates a stack of delegates without actually necessitating one.//對(duì)文檔進(jìn)行解析的實(shí)際作用類(lèi)BeanDefinitionParserDelegateBeanDefinitionParserDelegate parent = this.delegate;this.delegate = createHelper(readerContext, root, parent);preProcessXml(root);//利用BeanDefinitionParserDelegate進(jìn)行解析的入口方法parseBeanDefinitions(root, this.delegate);postProcessXml(root);this.delegate = parent; }//DefaultBeanDefinitionDocumentReader中的parseBeanDefinitions方法 //遍歷子節(jié)點(diǎn),也就是XML文件中的標(biāo)簽,依次解析 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)) {parseDefaultElement(ele, delegate);}else {delegate.parseCustomElement(ele);}}}}else {delegate.parseCustomElement(root);} }//DefaultBeanDefinitionDocumentReader中的parseDefaultElement方法 private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {//對(duì)"import"標(biāo)簽進(jìn)行處理if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {importBeanDefinitionResource(ele);}//對(duì)"alias"標(biāo)簽進(jìn)行處理else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {processAliasRegistration(ele);}//對(duì)"bean"標(biāo)簽進(jìn)行處理,是主要的解析標(biāo)簽。else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {processBeanDefinition(ele, delegate);}//對(duì)"beans"標(biāo)簽進(jìn)行處理else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {// recursedoRegisterBeanDefinitions(ele);} }//DefaultBeanDefinitionDocumentReader中的processBeanDefinition方法 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {//由BeanDefinitionParserDelegate負(fù)責(zé)解析,BeanDefinitionHolder是BeanDefinition的//封裝類(lèi),用于完成向IoC容器的注冊(cè)BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);if (bdHolder != null) {bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);try {// Register the final decorated instance.//載入解析完,注冊(cè)的入口函數(shù)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));} }


  • 具體的Spring BeanDefinition的解析是在BeanDefinitionParserDelegate中完成的。這個(gè)類(lèi)里包含了對(duì)各種Spri-ngBean定義規(guī)則的處理,感興趣可以仔細(xì)研究。比如我們最熟悉的對(duì)Bean元素的處理是怎樣完成的,也就是怎樣處理在XML定義文件中出現(xiàn)的<bean></bean>這個(gè)最常見(jiàn)的元素信息。在這里會(huì)看到對(duì)那些熟悉的Bean定義的處理,比如id, name, aliase等屬性元素。把這些元素的值從XML文件相應(yīng)的元素的屬性中讀取出來(lái)以后,設(shè)置到生成的BeanDefinitionHolder中去。這些屬性的解析還是比較簡(jiǎn)單的。對(duì)于其他元素配置的解析,比如各種Bean的屬性配置,通過(guò)一個(gè)較為復(fù)雜的解析過(guò)程,這個(gè)過(guò)程是由parseBeanDefinitionElement來(lái)完成的。解析完成以后。會(huì)把解析結(jié)果放到BeanDefinition對(duì)象中并設(shè)置到BeanDefinitionHolder中去。具體代碼如下:


//BeanDefinitionParserDelegate中的parseBeanDefinitionElement方法。 //這里ele是<bean>標(biāo)簽,BeanDefinition可以看成是對(duì)<bean>定義的抽象,也就是存儲(chǔ)<bean>定義的數(shù)據(jù)結(jié)構(gòu), //里面封裝的數(shù)據(jù)大多都是跟<bean>相關(guān)的,比如init-method,destroy-method等等,具體可以查看源碼,有了 //這些數(shù)據(jù),IoC才能對(duì)Bean配置進(jìn)行處理。 public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {//這里取得在<bean>元素中定義的id,name和aliaes屬性的值 String id = ele.getAttribute(ID_ATTRIBUTE);String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);List<String> aliases = new ArrayList<String>();if (StringUtils.hasLength(nameAttr)) {String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_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);}//這里引發(fā)對(duì)Bean元素的詳細(xì)解析AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);//下面就是對(duì)解析后的結(jié)果進(jìn)行封裝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; }//BeanDefinitionParserDelegate中的parseBeanDefinitionElement方法 public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) {this.parseState.push(new BeanEntry(beanName));//這里只讀取定義的<bean>中設(shè)里的class名字.然后載入到BeanDefiniton中去,只是做個(gè)//記錄.并不涉及對(duì)象的實(shí)例化過(guò)程,對(duì)象的實(shí)例化實(shí)際上是在依核注入時(shí)完成的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);}//這里生成需要的BeanDefinition對(duì)象,為Bean定義信息的載入做準(zhǔn)備AbstractBeanDefinition bd = createBeanDefinition(className, parent);//這里對(duì)當(dāng)前的Bean元素進(jìn)行屬性解析.并設(shè)里description的信息parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));//從名字可以清楚地看到.這里是對(duì)各種<bean>元素的信息進(jìn)行解析的地方parseMetaElements(ele, bd);parseLookupOverrideSubElements(ele, bd.getMethodOverrides());parseReplacedMethodSubElements(ele, bd.getMethodOverrides());//解析<bean>的構(gòu)造函數(shù)設(shè)置parseConstructorArgElements(ele, bd);//解析<bean>的property設(shè)置parsePropertyElements(ele, bd);parseQualifierElements(ele, bd);bd.setResource(this.readerContext.getResource());bd.setSource(extractSource(ele));return bd;}//下面這些異常是在配JBean出現(xiàn)問(wèn)題時(shí)經(jīng)常會(huì)看到的,這些檢查是在createBeanDefinition//時(shí)進(jìn)行的,會(huì)檢查Bean的class設(shè)置是否正確,比如這個(gè)類(lèi)是否能找到。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;}


  • 上面是具體生成BeanDefinition的地方。在這里,我們舉一個(gè)對(duì)property進(jìn)行解析的例子來(lái)完成對(duì)整個(gè)BeanDefi-nition載入過(guò)程的分析,還是在類(lèi)BeanDefinitionParserDelegate的代碼中,一層一層地對(duì)BeanDefinition中的定義進(jìn)行解析,比如從屬性元素集合到具體的每一個(gè)屬性元素,然后才是對(duì)具體的屬性值的處理。根據(jù)解析結(jié)果,對(duì)這些屬性值的處理會(huì)被封裝成PropertyValue對(duì)象并設(shè)置到BeanDefinition對(duì)象中去,代碼如下:


//BeanDefinitionParserDelegate中的parsePropertyElements方法 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 (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {//在判斷是property元素后對(duì)該property元素進(jìn)行解析的過(guò)程parsePropertyElement((Element) node, bd);}}}//BeanDefinitionParserDelegate中的parsePropertyElement方法 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)有同名的property存在,則不進(jìn)行解析。直接返回。也就是說(shuō).//如果在同一個(gè)Bean中有同名的proper七y設(shè)里,那么起作用的只是第一個(gè)if (bd.getPropertyValues().contains(propertyName)) {error("Multiple 'property' definitions for property '" + propertyName + "'", ele);return;}//這里是解析property值的地方,這個(gè)解析結(jié)果會(huì)在下面封裝到PropertyValue對(duì)象中。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();}}//BeanDefinitionParserDelegate中的parsePropertyValue方法 //這里獲取property元素的值,也許是一個(gè)list或者其他 public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {String elementName = (propertyName != null) ?"<property> element for property '" + propertyName + "'" :"<constructor-arg> 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 && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&!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和valueboolean 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;}//如果是子元素,例如list,set等等,則對(duì)子元素進(jìn)行解析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;}}


  • 這里我們看看對(duì)子元素的解析過(guò)程,具體是分析對(duì)list標(biāo)簽的解析過(guò)程。其他標(biāo)簽的解析可閱讀源碼。代碼如下:


//BeanDefinitionParserDelegate中的parsePropertySubElement方法,對(duì)property的子標(biāo)簽進(jìn)行解析 public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {if (!isDefaultNamespace(ele)) {return parseNestedCustomElement(ele, bd);}//子標(biāo)簽為bean的解析else if (nodeNameEquals(ele, BEAN_ELEMENT)) {BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);if (nestedBd != null) {nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);}return nestedBd;}//子標(biāo)簽為ref的解析else if (nodeNameEquals(ele, REF_ELEMENT)) {// A generic reference to any name of any bean.String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);boolean toParent = false;if (!StringUtils.hasLength(refName)) {// A reference to the id of another bean in the same XML file.refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE);if (!StringUtils.hasLength(refName)) {// A reference to the id of another bean in a parent context.refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);toParent = true;if (!StringUtils.hasLength(refName)) {error("'bean', 'local' or 'parent' is required for <ref> element", ele);return null;}}}if (!StringUtils.hasText(refName)) {error("<ref> element contains empty target attribute", ele);return null;}RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);ref.setSource(extractSource(ele));return ref;}//子標(biāo)簽為idref的解析else if (nodeNameEquals(ele, IDREF_ELEMENT)) {return parseIdRefElement(ele);}//子標(biāo)簽為value的解析else if (nodeNameEquals(ele, VALUE_ELEMENT)) {return parseValueElement(ele, defaultValueType);}else if (nodeNameEquals(ele, NULL_ELEMENT)) {// It's a distinguished null value. Let's wrap it in a TypedStringValue// object in order to preserve the source location.TypedStringValue nullHolder = new TypedStringValue(null);nullHolder.setSource(extractSource(ele));return nullHolder;}//子標(biāo)簽為array的解析else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {return parseArrayElement(ele, bd);}//子標(biāo)簽為list的解析else if (nodeNameEquals(ele, LIST_ELEMENT)) {return parseListElement(ele, bd);}//子標(biāo)簽為set的解析else if (nodeNameEquals(ele, SET_ELEMENT)) {return parseSetElement(ele, bd);}//子標(biāo)簽為map的解析else if (nodeNameEquals(ele, MAP_ELEMENT)) {return parseMapElement(ele, bd);}else if (nodeNameEquals(ele, PROPS_ELEMENT)) {return parsePropsElement(ele);}else {error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);return null;}}//BeanDefinitionParserDelegate中的parseListElement方法,解析list標(biāo)簽,將解析結(jié)果封裝在ManagedList中。 public List parseListElement(Element collectionEle, BeanDefinition bd) {String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE);NodeList nl = collectionEle.getChildNodes();ManagedList<Object> target = new ManagedList<Object>(nl.getLength());target.setSource(extractSource(collectionEle));target.setElementTypeName(defaultElementType);target.setMergeEnabled(parseMergeAttribute(collectionEle));//開(kāi)始解析list下的標(biāo)簽parseCollectionElements(nl, target, bd, defaultElementType);return target;}protected void parseCollectionElements(NodeList elementNodes, Collection<Object> target, BeanDefinition bd, String defaultElementType) {for (int i = 0; i < elementNodes.getLength(); i++) {Node node = elementNodes.item(i);if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT)) {//加入到target中,target是一個(gè)ManagedList,同時(shí)開(kāi)始對(duì)下一層子元素的解析過(guò)程。是一個(gè)遞歸調(diào)用。target.add(parsePropertySubElement((Element) node, bd, defaultElementType));}}}


  • 經(jīng)過(guò)這樣逐層地解析,我們?cè)赬ML文件中定義的Bean信息就被整個(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í)行索引、查詢和操作。但是,重要的依賴注入實(shí)際上在這個(gè)時(shí)候還沒(méi)有發(fā)生,現(xiàn)在,在IoC容器BeanDefinition中存在的還只是一些靜態(tài)的配置信息。嚴(yán)格地說(shuō),這時(shí)候的容器還沒(méi)有完全起作用。要發(fā)揮容器的作用,還需要完成數(shù)據(jù)向容器的注冊(cè)。

轉(zhuǎn)載于:https://www.cnblogs.com/huangzefeng/p/10322411.html

總結(jié)

以上是生活随笔為你收集整理的BeanDefinition的载入和解析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。