国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

Spring4.3.x 淺析xml配置的解析過程(4)——解析bean標(biāo)簽及其所有子標(biāo)簽

2019-11-09 19:37:31
字體:
供稿:網(wǎng)友

概述


在使用ResourceLoader創(chuàng)建Resource對(duì)象一節(jié)中,我們探討了SPRing如何正確的查找我們指定的配置文件并為配置文件生成Resource對(duì)象。

在使用DocumentLoader創(chuàng)建Document對(duì)象一節(jié)中,我們又已經(jīng)解析了Spring通過xerces如何把Resource對(duì)象中的xml內(nèi)容轉(zhuǎn)換成Document對(duì)象。

在淺析Spring4使用XmlBeanDefinitionReader解析xml配置一文中,我們知道XmlBeanDefinitionReader使用BeanDefinitionDocumentReader接口的默認(rèn)實(shí)現(xiàn)DefaultBeanDefinitionDocumentReader把Document對(duì)象中包含的配置信息轉(zhuǎn)換成BeanDefinition對(duì)象并把它注冊(cè)到BeanDefintionRegistry對(duì)象中。在DefaultBeanDefinitionDocumentReader的實(shí)現(xiàn)中,它的責(zé)任是遍歷xml根節(jié)點(diǎn)下的子節(jié)點(diǎn),并把處理bean標(biāo)簽和自定義命名空間的標(biāo)簽(比如aop:,context:,p:等)的細(xì)節(jié)委托給BeanDefinitionParserDelegate對(duì)象,BeanDefinitionParserDelegate才是真正解析配置文件的地方。

下面我們就開始探討B(tài)eanDefinitionParserDelegate解析bean標(biāo)簽的過程。

約定:為了提高本文的可讀性,我把spring源碼中定義的常量替換為對(duì)應(yīng)的字面值。

(1)創(chuàng)建BeanDefinitionParserDelegate 對(duì)象 在DefaultBeanDefinitionDocumentReader中,調(diào)用createDelegate方法根據(jù)beans標(biāo)簽來創(chuàng)建和初始化BeanDefinitionParserDelegate 對(duì)象,見下面createDelegate方法的源碼。

protected BeanDefinitionParserDelegate createDelegate( XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) { // 創(chuàng)建delegate對(duì)象 BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext); // 初始化delegate對(duì)象 delegate.initDefaults(root, parentDelegate); return delegate; }

createDelegate方法中的root參數(shù)為xml配置中<beans>標(biāo)簽,它首先實(shí)例化一個(gè)BeanDefinitionParserDelegate對(duì)象,然后調(diào)用這個(gè)對(duì)象的initDefaults方法來初始化默認(rèn)值,這個(gè)方法的代碼如下。

public void initDefaults(Element root, BeanDefinitionParserDelegate parent) { // 計(jì)算默認(rèn)值 populateDefaults(this.defaults, (parent != null ? parent.defaults : null), root); this.readerContext.fireDefaultsRegistered(this.defaults); } protected void populateDefaults(DocumentDefaultsDefinition defaults, DocumentDefaultsDefinition parentDefaults, Element root) { String lazyInit = root.getAttribute("default-lazy-init"); if ("default".equals(lazyInit)) { // 繼承外層<beans>標(biāo)簽的屬性值,否則為false字符串 lazyInit = (parentDefaults != null ? parentDefaults.getLazyInit() : "false"); } defaults.setLazyInit(lazyInit); String merge = root.getAttribute("default-merge"); if ("default".equals(merge)) { // 繼承外層<beans>標(biāo)簽的屬性值,否則為false字符串 merge = (parentDefaults != null ? parentDefaults.getMerge() : "false"); } defaults.setMerge(merge); String autowire = root.getAttribute("default-autowire"); if ("default".equals(autowire)) { // 繼承外層<beans>標(biāo)簽的屬性值,否則為no字符串 autowire = (parentDefaults != null ? parentDefaults.getAutowire() : "no"); } defaults.setAutowire(autowire); defaults.setDependencyCheck(root.getAttribute("default-dependency-check")); if (root.hasAttribute("default-autowire-candidates")) { defaults.setAutowireCandidates(root.getAttribute("default-autowire-candidates")); } else if (parentDefaults != null) { // 繼承外層<beans>標(biāo)簽的屬性值 defaults.setAutowireCandidates(parentDefaults.getAutowireCandidates()); } if (root.hasAttribute("default-init-method")) { defaults.setInitMethod(root.getAttribute("default-init-method")); } else if (parentDefaults != null) { // 繼承外層<beans>標(biāo)簽的屬性值 defaults.setInitMethod(parentDefaults.getInitMethod()); } if (root.hasAttribute("default-destroy-method")) { defaults.setDestroyMethod(root.getAttribute("default-destroy-method")); } else if (parentDefaults != null) { // 繼承外層<beans>標(biāo)簽的屬性值 defaults.setDestroyMethod(parentDefaults.getDestroyMethod()); } defaults.setSource(this.readerContext.extractSource(root)); }

populateDefaults方法獲取<beans>標(biāo)簽的屬性值,如果beans標(biāo)簽上沒有指定屬性值并且外層還有beans標(biāo)簽時(shí),將沿用外層beans標(biāo)簽的。

(2)使用BeanDefinitionParserDelegate 對(duì)象處理<bean>標(biāo)簽 我們從DefaultBeanDefinitionDocumentReader使用BeanDefinitionParserDelegate解析<bean>標(biāo)簽的方法processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)開始,代碼如下。

/** * 解析bean節(jié)點(diǎn),并注冊(cè)BeanDefinition對(duì)象 */ protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { // 創(chuàng)建BeanDefinitionHolder BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { // 裝飾BeanDefinition bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // 注冊(cè)已經(jīng)創(chuàng)建好的BeanDefintion BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // 發(fā)送BeanDefinition注冊(cè)事件 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }

processBeanDefinition方法的ele參數(shù)為<bean>標(biāo)簽,這段代碼分成三步。第一步,根據(jù)傳入的Element對(duì)象(bean標(biāo)簽的)調(diào)用代理對(duì)象的parseBeanDefinitionElement(Element ele)方法創(chuàng)建BeanDefinitionHolder 對(duì)象,這個(gè)對(duì)象持有創(chuàng)建好的BeanDefinition對(duì)象、bean的id和bean的別名。

第二步,調(diào)用代理對(duì)象的decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder)來對(duì)BeanDefinition對(duì)象再加工,主要是解析<bean>標(biāo)簽中自定義屬性和自定義標(biāo)簽。

第三步,調(diào)用工具類BeanDefinitionReaderUtils的registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)方法,這個(gè)方法用于注冊(cè)創(chuàng)建好的BeanDefinition。

第三步已經(jīng)在淺析Spring4使用XmlBeanDefinitionReader解析xml配置部分探討了。這里我們深入的探討前兩步。

1. 創(chuàng)建BeanDefinitionHolder 對(duì)象


執(zhí)行BeanDefinitionParserDelegate的parseBeanDefinitionElement(Element ele)方法,代碼如下。

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) { return parseBeanDefinitionElement(ele, null); } public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { // 獲取id屬性 String id = ele.getAttribute("id"); // 獲取name屬性 String nameAttr = ele.getAttribute("name"); List<String> aliases = new ArrayList<String>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; "); aliases.addAll(Arrays.asList(nameArr)); } String beanName = id; if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { // 使用第一個(gè)alias作為id 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) { // 檢查id和別名是否已經(jīng)被使用了,如果已經(jīng)被其他bean占用,則會(huì)拋出異常 checkNameUniqueness(beanName, aliases, ele); } // 創(chuàng)建BeanDefinition對(duì)象 AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { if (!StringUtils.hasText(beanName)) { // 配置中沒有指定id屬性 try { if (containingBean != null) { // bean是另一個(gè)bean的內(nèi)部bean beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this.readerContext.getRegistry(), true); } else { // 為一個(gè)頂層bean生成id beanName = this.readerContext.generateBeanName(beanDefinition); 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); // 返回BeanDefinitionHolder對(duì)象 // 此對(duì)象持有生成的BeanDefinition對(duì)象和id以及別名列表 return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null; }

這部分代碼主要是檢查用戶給的bean id是否已經(jīng)被占用、為沒有id屬性值的bean創(chuàng)建id值以及調(diào)用parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean)方法來解析Element對(duì)象并創(chuàng)建BeanDefinition對(duì)象,最后創(chuàng)建一個(gè)BeanDefinitionHolder對(duì)象來封裝BeanDefinition對(duì)象、bean id和bean別名。

parseBeanDefinitionElement方法是解析<bean>節(jié)點(diǎn)的主要方法,在這里我們重點(diǎn)探討它。下面是BeanDefinitionParserDelegate的parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean)方法代碼。

/*** 創(chuàng)建BeanDefinition對(duì)象**/public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); String className = null; // 讀取<bean>節(jié)點(diǎn)的class屬性 if (ele.hasAttribute("class")) { className = ele.getAttribute("class").trim(); } try { String parent = null; // 讀取<bean>節(jié)點(diǎn)的parent屬性 if (ele.hasAttribute("parent")) { parent = ele.getAttribute("parent"); } // 創(chuàng)建一個(gè)GenericBeanDefinition對(duì)象 AbstractBeanDefinition bd = createBeanDefinition(className, parent); // 解析<bean>節(jié)點(diǎn)的屬性 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); // 獲取<desription>節(jié)點(diǎn)的值 bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description")); // 解析<meta>節(jié)點(diǎn) parseMetaElements(ele, bd); // 解析<lookup-method>節(jié)點(diǎn) parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); // 解析<replaced-method>節(jié)點(diǎn) parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); // 解析<constructor-arg>節(jié)點(diǎn) parseConstructorArgElements(ele, bd); // 解析<property>節(jié)點(diǎn) parsePropertyElements(ele, bd); // 解析<qualifier>節(jié)點(diǎn) parseQualifierElements(ele, bd); // 讓BeanDefinition持有當(dāng)前Resource對(duì)象 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ù)bean標(biāo)簽的內(nèi)容來實(shí)例化并初始化BeanDefinition對(duì)象。 parseBeanDefinitionElement方法制定了<bean>的解析流程,即BeanDefinition對(duì)象的創(chuàng)建和初始化流程,這個(gè)流程在parseBeanDefinitionElement方法中已經(jīng)非常明確,主要有8步(除去<description>標(biāo)簽),這里我就不畫流程圖了,下面我們直接來探討這個(gè)流程。

1.1 實(shí)例化BeanDefinition對(duì)象

parseBeanDefinitionElement方法調(diào)用BeanDefinitionParserDelegate的createBeanDefinition方法來創(chuàng)建BeanDefinition對(duì)象,這個(gè)方法的源碼如下。

protected AbstractBeanDefinition createBeanDefinition(String className, String parentName) throws ClassNotFoundException { return BeanDefinitionReaderUtils.createBeanDefinition( parentName, className, this.readerContext.getBeanClassLoader()); }

createBeanDefinition方法通過調(diào)用工具類BeanDefinitionReaderUtils的createBeanDefinition靜態(tài)方法來創(chuàng)建BeanDefinition對(duì)象,代碼如下。

public static AbstractBeanDefinition createBeanDefinition( String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException { GenericBeanDefinition bd = new GenericBeanDefinition(); bd.setParentName(parentName); if (className != null) { if (classLoader != null) { // 使用ClassLoader加載Class對(duì)象 bd.setBeanClass(ClassUtils.forName(className, classLoader)); } else { // 設(shè)置bean對(duì)于的class全名稱 bd.setBeanClassName(className); } } return bd; }

BeanDefinitionReaderUtils的createBeanDefinition方法創(chuàng)建一個(gè)GenericBeanDefinition對(duì)象,設(shè)置此對(duì)象的parent名稱,以及對(duì)應(yīng)的Class對(duì)象或者class全名稱。

1.2 解析<bean>標(biāo)簽屬性

在parseBeanDefinitionElement方法中調(diào)用BeanDefinitionParserDelegate的parseBeanDefinitionAttributes方法處理<bean>標(biāo)簽的屬性,parseBeanDefinitionAttributes方法的代碼如下。

public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, BeanDefinition containingBean, AbstractBeanDefinition bd) { // spring從4.0開始不再使用singleton屬性 if (ele.hasAttribute("singleton")) { error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele); } else if (ele.hasAttribute("scope")) { // 設(shè)置作用域 bd.setScope(ele.getAttribute("scope")); } else if (containingBean != null) { // 嵌套bean,則使用外面那個(gè)bean的作用域 bd.setScope(containingBean.getScope()); } if (ele.hasAttribute("abstract")) { bd.setAbstract("true".equals(ele.getAttribute("abstract"))); } String lazyInit = ele.getAttribute("lazy-init"); if ("default".equals(lazyInit)) { // 默認(rèn)為false字符串 lazyInit = this.defaults.getLazyInit(); } bd.setLazyInit("true".equals(lazyInit)); String autowire = ele.getAttribute("autowire"); bd.setAutowireMode(getAutowireMode(autowire)); String dependencyCheck = ele.getAttribute("dependency-check"); bd.setDependencyCheck(getDependencyCheck(dependencyCheck)); if (ele.hasAttribute("depends-on")) { String dependsOn = ele.getAttribute("depends-on"); bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, ",; ")); } String autowireCandidate = ele.getAttribute("autowire-candidate"); if ("".equals(autowireCandidate) || "default".equals(autowireCandidate)) { String candidatePattern = this.defaults.getAutowireCandidates(); if (candidatePattern != null) { String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern); bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName)); } } else { bd.setAutowireCandidate("true".equals(autowireCandidate)); } if (ele.hasAttribute("primary")) { bd.setPrimary("true".equals(ele.getAttribute("primary"))); } if (ele.hasAttribute("init-method")) { String initMethodName = ele.getAttribute("init-method"); if (!"".equals(initMethodName)) { bd.setInitMethodName(initMethodName); } } else { if (this.defaults.getInitMethod() != null) { bd.setInitMethodName(this.defaults.getInitMethod()); bd.setEnforceInitMethod(false); } } if (ele.hasAttribute("destroy-method")) { String destroyMethodName = ele.getAttribute("destroy-method"); bd.setDestroyMethodName(destroyMethodName); } else { if (this.defaults.getDestroyMethod() != null) { bd.setDestroyMethodName(this.defaults.getDestroyMethod()); bd.setEnforceDestroyMethod(false); } } if (ele.hasAttribute("factory-method")) { bd.setFactoryMethodName(ele.getAttribute("factory-method")); } if (ele.hasAttribute("factory-bean")) { bd.setFactoryBeanName(ele.getAttribute("factory-bean")); } return bd; } public int getAutowireMode(String attValue) { String att = attValue; if("default".equals(attValue)) { // 根據(jù)<beans>標(biāo)簽的default-autowire屬性值確定 att = this.defaults.getAutowire(); } // 不啟用自動(dòng)裝配 int autowire = 0; if("byName".equals(att)) { // 查找與屬性名稱相同的bean,并注入 autowire = 1; } else if("byType".equals(att)) { // 通過屬性的類型查找javaBean依賴的對(duì)象并為其注入 autowire = 2; } else if("constructor".equals(att)) { // 同byType一樣是通過類型查找依賴對(duì)象 // 與byType的區(qū)別:它不是使用Seter方法注入,而是使用構(gòu)造子注入 autowire = 3; } else if("autodetect".equals(att)) { // 在byType和constructor之間自動(dòng)的選擇注入方式 autowire = 4; } return autowire; } public int getDependencyCheck(String attValue) { String att = attValue; if ("default".equals(att)) { // 根據(jù)<beans>標(biāo)簽的default-dependency-check屬性值確定 att = this.defaults.getDependencyCheck(); } if ("all".equals(att)) { // 檢查所有屬性 return 3; } else if ("objects".equals(att)) { // 檢查對(duì)象的關(guān)聯(lián)關(guān)系 return 1; } else if ("simple".equals(att)) { // 檢查原始類型和String類型的屬性 return 2; } else { // 不檢查依賴 return 0; } }

parseBeanDefinitionAttributes方法主要是解析bean標(biāo)簽上的屬性,如果bean標(biāo)簽上有些屬性沒有設(shè)置,則將使用在<beans>標(biāo)簽上對(duì)應(yīng)的屬性值。

1.3 解析<meta>標(biāo)簽

在parseBeanDefinitionElement方法中調(diào)用BeanDefinitionParserDelegate的parseMetaElements方法處理<bean>標(biāo)簽的子標(biāo)簽<meta>,parseMetaElements方法的源碼如下。

public void parseMetaElements(Element ele, BeanMetadataAttributeaccessor attributeAccessor) { NodeList nl = ele.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, "meta")) { Element metaElement = (Element) node; String key = metaElement.getAttribute("key"); String value = metaElement.getAttribute("value"); BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value); attribute.setSource(extractSource(metaElement)); attributeAccessor.addMetadataAttribute(attribute); } } }

parseMetaElements方法掃描bean標(biāo)簽下的meta標(biāo)簽,并獲取meta標(biāo)簽上的key和value屬性值。這里要說明兩個(gè)方法,其一是isCandidateElement方法,它是判斷當(dāng)前節(jié)點(diǎn)是否需要要被處理的節(jié)點(diǎn),代碼如下。

/** * 判斷節(jié)點(diǎn)是否是待處理節(jié)點(diǎn) **/ private boolean isCandidateElement(Node node) { return (node instanceof Element && (isDefaultNamespace(node) || !isDefaultNamespace(node.getParentNode()))); }

具有以下條件中一條的節(jié)點(diǎn)是待處理節(jié)點(diǎn)。 a. 節(jié)點(diǎn)是Element對(duì)象,并且在默認(rèn)命名空間中。 b. 節(jié)點(diǎn)是Element對(duì)象,且它和它的父節(jié)點(diǎn)都不在默認(rèn)命名空間中。

其二是nodeNameEquals方法,它判斷節(jié)點(diǎn)的名稱是否為指定的字符串,代碼如下。

/** * 判斷節(jié)點(diǎn)名稱 **/ public boolean nodeNameEquals(Node node, String desiredName) { return desiredName.equals(node.getNodeName()) || desiredName.equals(getLocalName(node)); }

isCandidateElement和nodeNameEquals方法我們還會(huì)在下面的探討中見到,所以這里對(duì)他們都認(rèn)識(shí)一下。

1.4 解析<lookup-method>標(biāo)簽

<lookup-method>標(biāo)簽用于一個(gè)無(wú)狀態(tài)bean引用一個(gè)有狀態(tài)bean,也可以這樣說一個(gè)作用域廣的bean引用作用域小的bean,比如singleton bean應(yīng)用一個(gè)prototype bean、sesstion bean、request bean時(shí)。

在parseBeanDefinitionElement方法中調(diào)用BeanDefinitionParserDelegate的parseLookupOverrideSubElements方法處理<bean>標(biāo)簽的子標(biāo)簽<lookup-method>,parseLookupOverrideSubElements方法的源碼如下。

public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) { NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, "lookup-method")) { Element ele = (Element) node; // 方法名稱 String methodName = ele.getAttribute("name"); // 一個(gè)bean名稱,表示方法需要返回這個(gè)名稱的bean String beanRef = ele.getAttribute("bean"); LookupOverride override = new LookupOverride(methodName, beanRef); override.setSource(extractSource(ele)); overrides.addOverride(override); } } }

1.5 解析<replaced-method>標(biāo)簽

<replaced-method>用于修改非final bean中某個(gè)非private且非final方法的實(shí)現(xiàn)。一般的,如果一個(gè)方法不是只有包范圍內(nèi)訪問的的,那么可以直接通過繼承來重寫方法。但是如果要重寫的方法只有包范圍內(nèi)才可以訪問的,那么使用replaced-method方法是一個(gè)非常不錯(cuò)的選擇。

<replaced-method>的作用是重寫bean中的某個(gè)方法。在parseBeanDefinitionElement方法中調(diào)用BeanDefinitionParserDelegate的parseLookupOverrideSubElements方法處理<bean>標(biāo)簽的子標(biāo)簽<replaced-method>,parseReplacedMethodSubElements方法的源碼如下。

public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides) { NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, "replaced-method")) { Element replacedMethodEle = (Element) node; // 將被替換的方法名稱 String name = replacedMethodEle.getAttribute("name"); // 一個(gè)實(shí)現(xiàn)了MethodReplacer接口的bean名稱 String callback = replacedMethodEle.getAttribute("replacer"); ReplaceOverride replaceOverride = new ReplaceOverride(name, callback); // 搜索<replaced-method>的<arg-type>子標(biāo)簽 // <arg-type>標(biāo)簽用于指定方法的參數(shù)類型 List<Element> argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, "arg-type"); for (Element argTypeEle : argTypeEles) { // 獲取<arg-type>的值,這個(gè)值表示參數(shù)類型的全名稱 String match = argTypeEle.getAttribute("match"); match = (StringUtils.hasText(match) ? match : DomUtils.getTextValue(argTypeEle)); if (StringUtils.hasText(match)) { replaceOverride.addTypeIdentifier(match); } } replaceOverride.setSource(extractSource(replacedMethodEle)); overrides.addOverride(replaceOverride); } } }

1.6 解析<constructor-arg>標(biāo)簽

<constructor-arg>用于指定使用帶參構(gòu)造器來實(shí)例化bean的場(chǎng)景。

在parseBeanDefinitionElement方法中調(diào)用BeanDefinitionParserDelegate的parseConstructorArgElements方法處理<bean>標(biāo)簽的子標(biāo)簽<constructor-arg>,parseConstructorArgElements方法的源碼如下。

public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) { NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, "constructor-arg")) { parseConstructorArgElement((Element) node, bd); } } } public void parseConstructorArgElement(Element ele, BeanDefinition bd) { // 獲取參數(shù)索引 String indexAttr = ele.getAttribute("index"); // 獲取參數(shù)類型字符串 String typeAttr = ele.getAttribute("type"); // 獲取參數(shù)名稱 String nameAttr = ele.getAttribute("name"); if (StringUtils.hasLength(indexAttr)) { // 配置了index屬性 try { int index = Integer.parseInt(indexAttr); if (index < 0) { error("'index' cannot be lower than 0", ele); } else { try { this.parseState.push(new ConstructorArgumentEntry(index)); // 獲取參數(shù)值 Object value = parsePropertyValue(ele, bd, null); ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value); if (StringUtils.hasLength(typeAttr)) { valueHolder.setType(typeAttr); } if (StringUtils.hasLength(nameAttr)) { valueHolder.setName(nameAttr); } valueHolder.setSource(extractSource(ele)); if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) { error("Ambiguous constructor-arg entries for index " + index, ele); } else { bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder); } } finally { this.parseState.pop(); } } } catch (NumberFormatException ex) { error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele); } } else { // 沒配置index屬性 try { this.parseState.push(new ConstructorArgumentEntry()); // 獲取參數(shù)值 Object value = parsePropertyValue(ele, bd, null); ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value); if (StringUtils.hasLength(typeAttr)) { valueHolder.setType(typeAttr); } if (StringUtils.hasLength(nameAttr)) { valueHolder.setName(nameAttr); } valueHolder.setSource(extractSource(ele)); bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder); } finally { this.parseState.pop(); } } }

parseConstructorArgElement方法最重要的是通過調(diào)用BeanDefinitionParserDelegate的parsePropertyValue方法來獲取參數(shù)值,parsePropertyValue方法的代碼如下。

public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) { String elementName = (propertyName != null) ? "<property> element for property '" + propertyName + "'" : "<constructor-arg> element"; // 除了<description>和<meta>標(biāo)簽外,<property>和<constructor-arg>只允許存在一個(gè)用于獲取屬性或參數(shù)值的標(biāo)簽, // 比如ref, value, list, props, set, array, map, bean等 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") && !nodeNameEquals(node, "meta")) { // 檢查是否有多個(gè)值子標(biāo)簽 if (subElement != null) { error(elementName + " must not contain more than one sub-element", ele); } else { subElement = (Element) node; } } } boolean hasRefAttribute = ele.hasAttribute("ref"); boolean hasValueAttribute = ele.hasAttribute("value"); // ref和value屬性不能同時(shí)設(shè)置 // 有了ref或者value屬性值,不能再添加值標(biāo)簽 if ((hasRefAttribute && hasValueAttribute) || ((hasRefAttribute || hasValueAttribute) && subElement != null)) { error(elementName + " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele); } if (hasRefAttribute) { String refName = ele.getAttribute("ref"); // ref屬性不能為空 if (!StringUtils.hasText(refName)) { error(elementName + " contains empty 'ref' attribute", ele); } // 創(chuàng)建并返回RuntimeBeanReference對(duì)象 RuntimeBeanReference ref = new RuntimeBeanReference(refName); ref.setSource(extractSource(ele)); return ref; } else if (hasValueAttribute) { // 創(chuàng)建并返回TypedStringValue對(duì)象 TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute("value")); valueHolder.setSource(extractSource(ele)); return valueHolder; }else if (subElement != null) { return parsePropertySubElement(subElement, bd); } else { // 參數(shù)和屬性必須要有值 error(elementName + " must specify a ref or value", ele); return null; } }

parsePropertyValue方法主要是處理給定節(jié)點(diǎn)元素上的ref和value屬性值,如果沒有ref或者value屬性,則調(diào)用BeanDefinitionParserDelegate的parsePropertySubElement方法從<property>、<constroctor-arg>標(biāo)簽的非meta非description子標(biāo)簽中獲取值。下面是parsePropertySubElement方法的源代碼。

public Object parsePropertySubElement(Element ele, BeanDefinition bd) { return parsePropertySubElement(ele, bd, null); } public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) { if (!isDefaultNamespace(ele)) { // 處理非默認(rèn)命名空間中的<property>子標(biāo)簽 return parseNestedCustomElement(ele, bd); } else if (nodeNameEquals(ele, "bean")) { // 處理<property>下的bean標(biāo)簽 BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd); if (nestedBd != null) { nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd); } return nestedBd; } else if (nodeNameEquals(ele, "ref")) { // 處理<ref>標(biāo)簽 String refName = ele.getAttribute("bean"); boolean toParent = false; if (!StringUtils.hasLength(refName)) { // A reference to the id of another bean in the same XML file. // 一個(gè)bean名稱,這個(gè)bean來自同一個(gè)xml文件 refName = ele.getAttribute("local"); if (!StringUtils.hasLength(refName)) { // 一個(gè)bean名稱,這個(gè)bean來自于父類 refName = ele.getAttribute("parent"); 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; } else if (nodeNameEquals(ele, "idref")) { // 處理<idref>標(biāo)簽 return parseIdRefElement(ele); } else if (nodeNameEquals(ele, "value")) { // 處理<value>標(biāo)簽 return parseValueElement(ele, defaultValueType); } else if (nodeNameEquals(ele, "null")) { // 返回<null>標(biāo)簽代表的null值,并用TypedStringValue對(duì)象來包裝 TypedStringValue nullHolder = new TypedStringValue(null); nullHolder.setSource(extractSource(ele)); return nullHolder; } else if (nodeNameEquals(ele, "array")) { // 處理<array>標(biāo)簽 return parseArrayElement(ele, bd); } else if (nodeNameEquals(ele, "list")) { // 處理<list>標(biāo)簽 return parseListElement(ele, bd); } else if (nodeNameEquals(ele, "set")) { // 處理<set>標(biāo)簽 return parseSetElement(ele, bd); } else if (nodeNameEquals(ele, "map")) { // 處理<map>標(biāo)簽 return parseMapElement(ele, bd); } else if (nodeNameEquals(ele, "props")) { // 處理<props>標(biāo)簽 return parsePropsElement(ele); } else { // 值標(biāo)簽必須要提供一個(gè)值 error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele); return null; } }

parsePropertySubElement方法處理<property>和<constructor-arg>標(biāo)簽下的bean,ref, idref, value, null, array, list, set, map, props以及其他命名空間中的標(biāo)簽,并返回這些標(biāo)簽所代表的值。其中bean、ref和null標(biāo)簽的處理已經(jīng)這個(gè)方法中體現(xiàn)了,下面我們來探討剩下7個(gè)標(biāo)簽如何處理的(這節(jié)不會(huì)討論其他命名空間的標(biāo)簽如何處理)。

(1) 處理<idref>標(biāo)簽

<idref>標(biāo)簽不常用,一般只用于注入容器中某個(gè)bean的名稱或者id。它和<property>的value屬性以及<value>標(biāo)簽值一樣,只是<idref>的bean、local屬性值必須為存在于容器中bean的id或name屬性值一致,否則會(huì)拋異常。

parsePropertySubElement方法調(diào)用BeanDefinitionParserDelegate的parseIdRefElement方法來處理<idref>標(biāo)簽,parseIdRefElement方法代碼如下。

public Object parseIdRefElement(Element ele) { // 獲取bean屬性值 String refName = ele.getAttribute("bean"); if (!StringUtils.hasLength(refName)) { // 獲取local屬性值,該值與同一個(gè)xml文件中某個(gè)bean的名稱相同 refName = ele.getAttribute("local"); if (!StringUtils.hasLength(refName)) { error("Either 'bean' or 'local' is required for <idref> element", ele); return null; } } if (!StringUtils.hasText(refName)) { error("<idref> element contains empty target attribute", ele); return null; } RuntimeBeanNameReference ref = new RuntimeBeanNameReference(refName); ref.setSource(extractSource(ele)); return ref; }

(2) 處理<value>標(biāo)簽

<value>標(biāo)簽用于指定一個(gè)字面值,可以是基本類型,字符串。

parsePropertySubElement方法調(diào)用BeanDefinitionParserDelegate的parseValueElement方法來處理<value>標(biāo)簽,parseValueElement方法代碼如下。

public Object parseValueElement(Element ele, String defaultTypeName) { // 獲取<value>標(biāo)簽的字面值 String value = DomUtils.getTextValue(ele); // 獲取type屬性,表示屬性值的類型的全名稱 String specifiedTypeName = ele.getAttribute("type"); String typeName = specifiedTypeName; if (!StringUtils.hasText(typeName)) { typeName = defaultTypeName; } try { // 根據(jù)value值和值類型創(chuàng)建TypedStringValue對(duì)象 TypedStringValue typedValue = buildTypedStringValue(value, typeName); typedValue.setSource(extractSource(ele)); typedValue.setSpecifiedTypeName(specifiedTypeName); return typedValue; } catch (ClassNotFoundException ex) { error("Type class [" + typeName + "] not found for <value> element", ele, ex); return value; } }

parseValueElement方法獲取<value>標(biāo)簽的字面值和type屬性后通過buildTypedStringValue方法創(chuàng)建TypedStringValue 對(duì)象,buildTypedStringValue方法的代碼如下。

protected TypedStringValue buildTypedStringValue(String value, String targetTypeName) throws ClassNotFoundException { ClassLoader classLoader = this.readerContext.getBeanClassLoader(); TypedStringValue typedValue; if (!StringUtils.hasText(targetTypeName)) { typedValue = new TypedStringValue(value); } else if (classLoader != null) { // 通過ClassLoader對(duì)象來加載一個(gè)Class對(duì)象 Class<?> targetType = ClassUtils.forName(targetTypeName, classLoader); typedValue = new TypedStringValue(value, targetType); } else { typedValue = new TypedStringValue(value, targetTypeName); } return typedValue; }

(3) 處理<array>標(biāo)簽

<array>標(biāo)簽用于指定一個(gè)數(shù)組對(duì)象。

parsePropertySubElement方法調(diào)用BeanDefinitionParserDelegate的parseArrayElement方法來處理<array>標(biāo)簽,parseArrayElement方法代碼如下。

public Object parseArrayElement(Element arrayEle, BeanDefinition bd) { // 獲取元素的value-type屬性值,它表示元素的類型 String elementType = arrayEle.getAttribute("value-type"); NodeList nl = arrayEle.getChildNodes(); ManagedArray target = new ManagedArray(elementType, nl.getLength()); target.setSource(extractSource(arrayEle)); target.setElementTypeName(elementType); // 獲取并設(shè)置merge屬性值 target.setMergeEnabled(parseMergeAttribute(arrayEle)); // 處理子標(biāo)簽 parseCollectionElements(nl, target, bd, elementType); return target; } /** * 獲取元素的merge屬性值 **/ public boolean parseMergeAttribute(Element collectionElement) { String value = collectionElement.getAttribute("merge"); if ("default".equals(value)) { value = this.defaults.getMerge(); } return "true".equals(value); }

parseArrayElement方法主要是獲取<array>標(biāo)簽中的value-type屬性值和merge屬性值來創(chuàng)建一個(gè)實(shí)現(xiàn)了Collection接口的ManagedArray對(duì)象,然后調(diào)用BeanDefinitionParserDelegate中處理集合元素子標(biāo)簽的parseCollectionElements方法,這個(gè)方法的源碼如下。

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")) { // 遞歸調(diào)用parsePropertySubElement方法來解析子節(jié)點(diǎn)。 target.add(parsePropertySubElement((Element) node, bd, defaultElementType)); } } }

parseCollectionElements方法遍歷集合標(biāo)簽(array、set和list)下的子標(biāo)簽,并遞歸調(diào)用處理<property>、<constructor-arg>標(biāo)簽的子標(biāo)簽的parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType)方法。

(4) 處理<list>標(biāo)簽

<list>標(biāo)簽用于指定一個(gè)List對(duì)象

parsePropertySubElement方法調(diào)用BeanDefinitionParserDelegate的parseListElement方法來處理<list>標(biāo)簽,parseListElement方法代碼如下。

public List<Object> parseListElement(Element collectionEle, BeanDefinition bd) { // 獲取元素的value-type屬性值,它表示元素的類型 String defaultElementType = collectionEle.getAttribute("value-type"); NodeList nl = collectionEle.getChildNodes(); ManagedList<Object> target = new ManagedList<Object>(nl.getLength()); target.setSource(extractSource(collectionEle)); target.setElementTypeName(defaultElementType); // 獲取并設(shè)置merge屬性值 target.setMergeEnabled(parseMergeAttribute(collectionEle)); // 處理子標(biāo)簽 parseCollectionElements(nl, target, bd, defaultElementType); return target; }

parseListElement方法主要是獲取<list>標(biāo)簽中的value-type屬性值和merge屬性值來創(chuàng)建一個(gè)實(shí)現(xiàn)了Collection接口的ManagedList對(duì)象,然后調(diào)用BeanDefinitionParserDelegate中處理集合元素子標(biāo)簽的parseCollectionElements方法。

(5) 處理<set>標(biāo)簽

<set>標(biāo)簽用于指定一個(gè)Set對(duì)象。

parsePropertySubElement方法調(diào)用BeanDefinitionParserDelegate的parseSetElement方法來處理<set>標(biāo)簽,parseSetElement方法代碼如下。

public Set<Object> parseSetElement(Element collectionEle, BeanDefinition bd) { // 獲取元素的value-type屬性值,它表示元素的類型 String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE); NodeList nl = collectionEle.getChildNodes(); ManagedSet<Object> target = new ManagedSet<Object>(nl.getLength()); target.setSource(extractSource(collectionEle)); target.setElementTypeName(defaultElementType); // 獲取并設(shè)置merge屬性值 target.setMergeEnabled(parseMergeAttribute(collectionEle)); // 處理子標(biāo)簽 parseCollectionElements(nl, target, bd, defaultElementType); return target; }

parseSetElement方法主要是獲取<set>標(biāo)簽中的value-type屬性值和merge屬性值來創(chuàng)建一個(gè)實(shí)現(xiàn)了Collection接口的ManagedSet對(duì)象,然后調(diào)用BeanDefinitionParserDelegate中處理集合元素子標(biāo)簽的parseCollectionElements方法。

(6) 處理<map>標(biāo)簽

<map>標(biāo)簽用于指定一個(gè)Map對(duì)象。

parsePropertySubElement方法調(diào)用BeanDefinitionParserDelegate的parseMapElement方法來處理<map>標(biāo)簽,parseMapElement方法代碼如下。

public Map<Object, Object> parseMapElement(Element mapEle, BeanDefinition bd) { // 獲取Map中key值的類型 String defaultKeyType = mapEle.getAttribute("key-type"); // 獲取Map中value值得類型 String defaultValueType = mapEle.getAttribute("value-type"); // 獲取<map>標(biāo)簽下的所有<entry>子標(biāo)簽 List<Element> entryEles = DomUtils.getChildElementsByTagName(mapEle, "entry"); ManagedMap<Object, Object> map = new ManagedMap<Object, Object>(entryEles.size()); map.setSource(extractSource(mapEle)); map.setKeyTypeName(defaultKeyType); map.setValueTypeName(defaultValueType); // 獲取并設(shè)置merge屬性值 map.setMergeEnabled(parseMergeAttribute(mapEle)); for (Element entryEle : entryEles) { NodeList entrySubNodes = entryEle.getChildNodes(); Element keyEle = null; Element valueEle = null; // 獲取<entry>標(biāo)簽下的<key>和值標(biāo)簽 for (int j = 0; j < entrySubNodes.getLength(); j++) { Node node = entrySubNodes.item(j); if (node instanceof Element) { Element candidateEle = (Element) node; if (nodeNameEquals(candidateEle, "key")) { // 獲取key標(biāo)簽 if (keyEle != null) { error("<entry> element is only allowed to contain one <key> sub-element", entryEle); } else { keyEle = candidateEle; } } else { // 獲取值標(biāo)簽 if (nodeNameEquals(candidateEle, "description")) { // 忽略<description> } else if (valueEle != null) { error("<entry> element must not contain more than one value sub-element", entryEle); } else { valueEle = candidateEle; } } } } // 從<entry>的屬性key或者key-ref或者子標(biāo)簽<key>獲取Map中元素的key值 Object key = null; boolean hasKeyAttribute = entryEle.hasAttribute("key"); boolean hasKeyRefAttribute = entryEle.hasAttribute("key-ref"); // 相同意義的標(biāo)簽和屬性不能共存 if ((hasKeyAttribute && hasKeyRefAttribute) || ((hasKeyAttribute || hasKeyRefAttribute)) && keyEle != null) { error("<entry> element is only allowed to contain either " + "a 'key' attribute OR a 'key-ref' attribute OR a <key> sub-element", entryEle); } if (hasKeyAttribute) { // 處理屬性key值 key = buildTypedStringValueForMap(entryEle.getAttribute("key"), defaultKeyType, entryEle); } else if (hasKeyRefAttribute) { // 處理屬性key-ref值 String refName = entryEle.getAttribute("key-ref"); if (!StringUtils.hasText(refName)) { error("<entry> element contains empty 'key-ref' attribute", entryEle); } RuntimeBeanReference ref = new RuntimeBeanReference(refName); ref.setSource(extractSource(entryEle)); key = ref; } else if (keyEle != null) { // 處理<key>標(biāo)簽 key = parseKeyElement(keyEle, bd, defaultKeyType); } else { error("<entry> element must specify a key", entryEle); } // 從<entry>的屬性value或者value-ref或者子值標(biāo)簽(value,array,bean,map等)獲取Map中元素的value值 Object value = null; boolean hasValueAttribute = entryEle.hasAttribute("value"); boolean hasValueRefAttribute = entryEle.hasAttribute("value-ref"); boolean hasValueTypeAttribute = entryEle.hasAttribute("value-type"); // 相同意義的標(biāo)簽和屬性不能共存 // value、value-ref、值子標(biāo)簽不能同時(shí)存在 if ((hasValueAttribute && hasValueRefAttribute) || ((hasValueAttribute || hasValueRefAttribute)) && valueEle != null) { error("<entry> element is only allowed to contain either " + "'value' attribute OR 'value-ref' attribute OR <value> sub-element", entryEle); } // 有value-type屬性值,則必須有value屬性值,且不能有value-ref值和子值標(biāo)簽 if ((hasValueTypeAttribute && hasValueRefAttribute) || (hasValueTypeAttribute && !hasValueAttribute) || (hasValueTypeAttribute && valueEle != null)) { error("<entry> element is only allowed to contain a 'value-type' " + "attribute when it has a 'value' attribute", entryEle); } if (hasValueAttribute) { // 處理value和value-type屬性值 String valueType = entryEle.getAttribute("value-type"); if (!StringUtils.hasText(valueType)) { valueType = defaultValueType; } value = buildTypedStringValueForMap(entryEle.getAttribute("value"), valueType, entryEle); } else if (hasValueRefAttribute) { // 處理value-ref屬性值 String refName = entryEle.getAttribute("value-ref"); if (!StringUtils.hasText(refName)) { error("<entry> element contains empty 'value-ref' attribute", entryEle); } RuntimeBeanReference ref = new RuntimeBeanReference(refName); ref.setSource(extractSource(entryEle)); value = ref; } else if (valueEle != null) { // 處理值標(biāo)簽,遞歸調(diào)用parsePropertySubElement方法 value = parsePropertySubElement(valueEle, bd, defaultValueType); } else { error("<entry> element must specify a value", entryEle); } map.put(key, value); } return map; } /** * 處理<entry>上的屬性key或value值。返回一個(gè)TypedStringValue對(duì)象 **/ protected final Object buildTypedStringValueForMap(String value, String defaultTypeName, Element entryEle) { try { // 創(chuàng)建TypedStringValue對(duì)象 TypedStringValue typedValue = buildTypedStringValue(value, defaultTypeName); typedValue.setSource(extractSource(entryEle)); return typedValue; } catch (ClassNotFoundException ex) { error("Type class [" + defaultTypeName + "] not found for Map key/value type", entryEle, ex); return value; } } /** * 處理entry標(biāo)簽下的key標(biāo)簽 **/ protected Object parseKeyElement(Element keyEle, BeanDefinition bd, String defaultKeyTypeName) { NodeList nl = keyEle.getChildNodes(); Element subElement = null; // 遍歷<key>標(biāo)簽下的子標(biāo)簽 for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { if (subElement != null) { error("<key> element must not contain more than one value sub-element", keyEle); } else { subElement = (Element) node; } } } return parsePropertySubElement(subElement, bd, defaultKeyTypeName); }

(7) 處理<props>標(biāo)簽

<props>標(biāo)簽用于指定一個(gè)Property對(duì)象。

parsePropertySubElement方法調(diào)用BeanDefinitionParserDelegate的parsePropsElement方法來處理<props>標(biāo)簽,parsePropsElement方法代碼如下。

public Properties parsePropsElement(Element propsEle) { ManagedProperties props = new ManagedProperties(); props.setSource(extractSource(propsEle)); props.setMergeEnabled(parseMergeAttribute(propsEle)); // 獲取并遍歷所有的<prop>標(biāo)簽 List<Element> propEles = DomUtils.getChildElementsByTagName(propsEle, "prop"); for (Element propEle : propEles) { // 獲取<prop>標(biāo)簽的key屬性值 String key = propEle.getAttribute("key"); // 以<prop>標(biāo)簽的字面值為value值 String value = DomUtils.getTextValue(propEle).trim(); // 用key值創(chuàng)建TypedStringValue對(duì)象 TypedStringValue keyHolder = new TypedStringValue(key); keyHolder.setSource(extractSource(propEle)); // 用value值創(chuàng)建TypedStringValue TypedStringValue valueHolder = new TypedStringValue(value); valueHolder.setSource(extractSource(propEle)); props.put(keyHolder, valueHolder); } return props; }

parsePropsElement方法遍歷并獲取<props>標(biāo)簽下的所有<prop>標(biāo)簽的key值和字面值。

1.7 解析<property>標(biāo)簽

在parseBeanDefinitionElement方法中調(diào)用BeanDefinitionParserDelegate的parsePropertyElements方法處理<bean>標(biāo)簽的子標(biāo)簽<property>,parsePropertyElements方法的源碼如下。

public void parsePropertyElements(Element beanEle, BeanDefinition bd) { NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); // 查找<property>標(biāo)簽 if (isCandidateElement(node) && nodeNameEquals(node, "property")) { parsePropertyElement((Element) node, bd); } } }

parsePropertyElements方法主要是搜索bean標(biāo)簽下的<property>標(biāo)簽,每找到一個(gè)<property>標(biāo)簽就調(diào)用parsePropertyElement方法來處理此標(biāo)簽,parsePropertyElement方法代碼如下。

public void parsePropertyElement(Element ele, BeanDefinition bd) { // 獲取name屬性值,這值必須與bean中的屬性名稱相同 String propertyName = ele.getAttribute("name"); if (!StringUtils.hasLength(propertyName)) { error("Tag 'property' must have a 'name' attribute", ele); return; } this.parseState.push(new PropertyEntry(propertyName)); try { if (bd.getPropertyValues().contains(propertyName)) { error("Multiple 'property' definitions for property '" + propertyName + "'", ele); return; } // 獲取屬性值 Object val = parsePropertyValue(ele, bd, propertyName); // 創(chuàng)建PropertyValue對(duì)象 PropertyValue pv = new PropertyValue(propertyName, val); parseMetaElements(ele, pv); pv.setSource(extractSource(ele)); // 保存PropertyValue對(duì)象 bd.getPropertyValues().addPropertyValue(pv); } finally { this.parseState.pop(); } }

和處理<constructor-arg>標(biāo)簽一樣,parsePropertyElement方法也是調(diào)用BeanDefinitionParserDelegate的parsePropertyValue方法來獲取對(duì)應(yīng)的值。

1.8 解析<qualifier>標(biāo)簽

在parseBeanDefinitionElement方法中調(diào)用BeanDefinitionParserDelegate的parseQualifierElements方法處理<bean>標(biāo)簽的子標(biāo)簽<qualifier>,parseQualifierElements方法的源碼如下。

public void parseQualifierElements(Element beanEle, AbstractBeanDefinition bd) { NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, "qualifier")) { parseQualifierElement((Element) node, bd); } } }

parseQualifierElements方法主要是搜索并處理<bean>標(biāo)簽下所有的<qualifier>標(biāo)簽,沒搜索到一個(gè)<qualifier>標(biāo)簽,就會(huì)調(diào)用BeanDefinitionParserDelegate的parseQualifierElement方法來處理,parseQualifierElement方法的源代碼如下。

/** * 向BeanDefinition對(duì)象中添加AutowireCandidateQualifier對(duì)象 **/ public void parseQualifierElement(Element ele, AbstractBeanDefinition bd) { String typeName = ele.getAttribute("type"); // <qualifier>標(biāo)簽必須要有type屬性 if (!StringUtils.hasLength(typeName)) { error("Tag 'qualifier' must have a 'type' attribute", ele); return; } this.parseState.push(new QualifierEntry(typeName)); try { AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(typeName); qualifier.setSource(extractSource(ele)); // 獲取<qualifier>的value屬性 String value = ele.getAttribute("value"); if (StringUtils.hasLength(value)) { qualifier.setAttribute("value", value); } NodeList nl = ele.getChildNodes(); // 搜索<attribute>標(biāo)簽 for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, "attribute")) { Element attributeEle = (Element) node; // 獲取<attribute>標(biāo)簽的key屬性值 String attributeName = attributeEle.getAttribute("key"); // 獲取<attribute>標(biāo)簽的value屬性值 String attributeValue = attributeEle.getAttribute("value"); if (StringUtils.hasLength(attributeName) && StringUtils.hasLength(attributeValue)) { BeanMetadataAttribute attribute = new BeanMetadataAttribute(attributeName, attributeValue); attribute.setSource(extractSource(attributeEle)); qualifier.addMetadataAttribute(attribute); } else { // 定義了<attribute>標(biāo)簽就必須要提供key和value屬性值 error("Qualifier 'attribute' tag must have a 'name' and 'value'", attributeEle); return; } } } bd.addQualifier(qualifier); } finally { this.parseState.pop(); } }

<qualifier>標(biāo)簽用于給bean創(chuàng)建限制標(biāo)識(shí)符,其中type屬性為一個(gè)注解類的全名稱,spring默認(rèn)為org.springframework.beans.factory.annotation.Qualifier;value值為bean的標(biāo)識(shí)符,可為空;<attribute>標(biāo)簽的key和value分別表示注解對(duì)象的方法名和方法返回值。

<qualifier>作用是區(qū)別相同類型的不同bean。個(gè)人覺得,它的好處是可以指定一個(gè)注解來代表一個(gè)bean,以免在代碼中hard-code bean的名稱,但所指定的注解必須要用@Qualifier注解標(biāo)注。

qualifier的替代方案:我們可以用id屬性值或者name屬性值來替代<qualifier>標(biāo)簽。同樣可以自定義一個(gè)注解類來代表一個(gè)bean,只是此時(shí)的@Qualifier的value方法的返回值必須與id屬性或者name屬性對(duì)應(yīng)。本人覺得如果id屬性值或者name屬性值不會(huì)經(jīng)常改變時(shí),這比使用<qualifier>標(biāo)簽更方便。

2. 裝飾BeanDefinition對(duì)象


DefaultBeanDefinitionDocumentReader對(duì)象的processBeanDefinition方法在調(diào)用BeanDefinitionParserDelegate對(duì)象的parseBeanDefinitionElement方法解析<bean>標(biāo)簽并獲得持有BeanDefintion對(duì)象的BeanDefinitionHolder對(duì)象后,繼續(xù)調(diào)用BeanDefinitionParserDelegate對(duì)象的decorateBeanDefinitionIfRequired來對(duì)剛獲得BeanDefintion對(duì)象做進(jìn)一步的加工處理。

這一部分的加工處理主要是處理<bean>標(biāo)簽中非默認(rèn)命名空間中的屬性或者子標(biāo)簽,比如p:命名空間修飾的屬性。我們來看看BeanDefinitionParserDelegate的decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder)方法代碼,如下。

public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) { return decorateBeanDefinitionIfRequired(ele, definitionHolder, null); } public BeanDefinitionHolder decorateBeanDefinitionIfRequired( Element ele, BeanDefinitionHolder definitionHolder, BeanDefinition containingBd) { BeanDefinitionHolder finalDefinition = definitionHolder; // 首先根據(jù)自定義屬性裝飾BeanDefinition // 比如http://www.springframework.org/schema/p命名空間的屬性 NamedNodeMap attributes = ele.getAttributes(); for (int i = 0; i < attributes.getLength(); i++) { Node node = attributes.item(i); finalDefinition = decorateIfRequired(node, finalDefinition, containingBd); } // 根據(jù)嵌套的自定義標(biāo)簽元素裝飾BeanDefinition NodeList children = ele.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { Node node = children.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { finalDefinition = decorateIfRequired(node, finalDefinition, containingBd); } } return finalDefinition; }

這段代碼的責(zé)任是遍歷標(biāo)簽的屬性和子節(jié)點(diǎn)并調(diào)用decorateIfRequired(Node node, BeanDefinitionHolder originalDef, BeanDefinition containingBd)方法來處理屬性和<bean>的子標(biāo)簽,詳見以下代碼。

/** * 處理自定義命名空間標(biāo)簽來裝飾BeanDefinition對(duì)象 **/ private BeanDefinitionHolder decorateIfRequired( Node node, BeanDefinitionHolder originalDef, BeanDefinition containingBd) { String namespaceUri = getNamespaceURI(node); if (!isDefaultNamespace(namespaceUri)) { // 根據(jù)節(jié)點(diǎn)所在的命名空間,獲取NamespaceHandler對(duì)象 // 比如http://www.springframework.org/schema/p命名空間的為SimplePropertyNamespaceHandler NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler != null) { // 執(zhí)行裝飾BeanDefinition對(duì)象 return handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd)); } else if (namespaceUri != null && namespaceUri.startsWith("http://www.springframework.org/")) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node); } else { // 節(jié)點(diǎn)為自定義命名空間的,但沒有指定NamespaceHandler if (logger.isDebugEnabled()) { logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]"); } } } return originalDef; }

decorateIfRequired方法只處理非默認(rèn)命名空間的屬性和標(biāo)簽,因此它首先會(huì)檢查節(jié)點(diǎn)是否為默認(rèn)明見中的,是默認(rèn)空間的則直接返回,如果不是則調(diào)用NamespaceHandlerResolver對(duì)象(默認(rèn)為DefaultNamespaceHandlerResolver)來獲得節(jié)點(diǎn)所在命名空間的處理器NamespaceHandler對(duì)象,然后調(diào)用NamespaceHandler對(duì)象的decorate方法,并返回一個(gè)BeanDefinitionHolder 對(duì)象,它可以是新創(chuàng)建的,也可以是裝飾前的那個(gè)。

總結(jié)


(1) 可以通過給<beans>指定屬性值來全局性的設(shè)置<bean>標(biāo)簽對(duì)應(yīng)的屬性值,比如定義全局的初始化方法,則可以在<beans>定義default-init-method屬性值。

(2)<property>和<constructor-arg>標(biāo)簽使用同一套屬性名和子標(biāo)簽。


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 德清县| 达拉特旗| 高碑店市| 若尔盖县| 招远市| 策勒县| 镇远县| 前郭尔| 江山市| 新乡市| 敖汉旗| 丹阳市| 炉霍县| 麻江县| 大丰市| 延长县| 淳化县| 永仁县| 诸暨市| 嘉鱼县| 武安市| 广州市| 巴里| 左贡县| 绥宁县| 泽库县| 长海县| 云霄县| 渭源县| 清水县| 临洮县| 马山县| 海盐县| 柞水县| 会同县| 阿拉善盟| 长沙县| 禄丰县| 高碑店市| 襄汾县| 龙泉市|