摘要:在上一篇文章中,分析了容器的創(chuàng)建,加載資源文件,將資源文件讀取為。將文件中的注冊(cè)定義的對(duì)象。在中對(duì)屬性的解析委托給這個(gè)代理類來實(shí)現(xiàn)的。首先,獲取節(jié)點(diǎn)。
在上一篇文章中,分析了ApplicationContext容器的創(chuàng)建,加載資源文件,將資源文件讀取為Document。spring將xml文件中的Bean注冊(cè)spring定義的BeanDefinition對(duì)象。在DefaultBeanDefinitionDocumentReader中對(duì)Document屬性的解析委托給BeanDefinitionParserDelegate這個(gè)代理類來實(shí)現(xiàn)的。
Bean注冊(cè)前的準(zhǔn)備DefaultBeanDefinitionDocumentReader的registerBeanDefinitions方法實(shí)現(xiàn)如下,首先獲取Document的根元素,接著調(diào)用doRegisterBeanDefinitions(root)進(jìn)行注冊(cè)
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; //獲取根元素 Element root = doc.getDocumentElement(); //注冊(cè)BeanDefinition doRegisterBeanDefinitions(root); }
doRegisterBeanDefinitions(root)方法的實(shí)現(xiàn)如下:
protected void doRegisterBeanDefinitions(Element root) { //獲取代理類 BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createDelegate(getReaderContext(), root, parent); //是否為默認(rèn)命名空間 if (this.delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); //是否有profile屬性 if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { return; } } } preProcessXml(root); //解析BeanDefinition parseBeanDefinitions(root, this.delegate); postProcessXml(root); this.delegate = parent; }根據(jù)不同節(jié)點(diǎn)名進(jìn)行解析
parseBeanDefinitions(root, this.delegate)方法是解析根源素下定義的每一個(gè)bean。首先,獲取節(jié)點(diǎn)List。其次,判斷每個(gè)元素是否為默認(rèn)的命名空間中的元素,然后交給不同的方法去解析,具體的實(shí)現(xiàn)如下:
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { //如果根元素為默認(rèn)命名空間中的元素 if (delegate.isDefaultNamespace(root)) { //獲取字元素List 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; //判斷此元素是否為默認(rèn)命名空間的元素 if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }spring默認(rèn)命名空間節(jié)點(diǎn)的解析
下面,我們首先看spring默認(rèn)命名空間元素的解析過程,parseDefaultElement(ele, delegate)方法的實(shí)現(xiàn)如下:
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { //節(jié)點(diǎn)名為import if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } //節(jié)點(diǎn)名為alias else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } //節(jié)點(diǎn)名為bean else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } //節(jié)點(diǎn)名為beans else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse 循環(huán)調(diào)用 doRegisterBeanDefinitions(ele); } }
import節(jié)點(diǎn)的解析
import元素是引入其他的配置文件,resource屬性是配置文件的路徑,importBeanDefinitionResource(ele)方法的實(shí)現(xiàn)如下,省略了異常處理代碼:
protected void importBeanDefinitionResource(Element ele) { //獲取resource屬性值,即其他配置文件的路徑 String location = ele.getAttribute(RESOURCE_ATTRIBUTE); // 解析路徑,如"${user.dir}" 這樣的路徑是從在propertie文件中加載的 location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location); SetactualResources = new LinkedHashSet<>(4); // 判斷l(xiāng)ocation 是絕對(duì)路徑還是相對(duì)路徑 boolean absoluteLocation = false; absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute(); // 絕對(duì)路徑 if (absoluteLocation) { //調(diào)用loadBeanDefinitions(location, actualResources)方法解析此配置文件 int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources); } } //相對(duì)路徑 else { int importCount; Resource relativeResource = getReaderContext().getResource().createRelative(location); if (relativeResource.exists()) { //調(diào)用loadBeanDefinitions(relativeResource)方法解析此配置文件 importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource); actualResources.add(relativeResource); } else { String baseLocation = getReaderContext().getResource().getURL().toString(); importCount = getReaderContext().getReader().loadBeanDefinitions( StringUtils.applyRelativePath(baseLocation, location), actualResources); } } } //廣播Import元素處理事件 Resource[] actResArray = actualResources.toArray(new Resource[0]); getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele)); }
alias節(jié)點(diǎn)的解析
下面介紹alias元素的方法,processAliasRegistration(ele)方法的實(shí)現(xiàn)如下:
protected void processAliasRegistration(Element ele) { //獲取name屬性 String name = ele.getAttribute(NAME_ATTRIBUTE); //獲取alias屬性 String alias = ele.getAttribute(ALIAS_ATTRIBUTE); boolean valid = true; if (!StringUtils.hasText(name)) { getReaderContext().error("Name must not be empty", ele); valid = false; } if (!StringUtils.hasText(alias)) { getReaderContext().error("Alias must not be empty", ele); valid = false; } if (valid) { //調(diào)用SimpleAliasRegistry類的registerAlias(name, alias)進(jìn)行注冊(cè) getReaderContext().getRegistry().registerAlias(name, alias); getReaderContext().fireAliasRegistered(name, alias, extractSource(ele)); } }
在SimpleAliasRegistry中定義了aliasMap來存儲(chǔ)alias和name的關(guān)系,具體實(shí)現(xiàn)如下:
private final MapaliasMap = new ConcurrentHashMap<>(16); public void registerAlias(String name, String alias) { Assert.hasText(name, ""name" must not be empty"); Assert.hasText(alias, ""alias" must not be empty"); synchronized (this.aliasMap) { //如果alias和name相等,將此關(guān)系移除 if (alias.equals(name)) { this.aliasMap.remove(alias); } else { //先從aliasMap獲取key為alias的beanName String registeredName = this.aliasMap.get(alias); if (registeredName != null) { //如果已存在,return if (registeredName.equals(name)) { // An existing alias - no need to re-register return; } //如果不存在,判斷alias是否可以繼承,默認(rèn)是true if (!allowAliasOverriding()) { throw new IllegalStateException("Cannot register alias "" + alias + "" for name "" + name + "": It is already registered for name "" + registeredName + ""."); } } //檢查是否存在循環(huán)依賴 checkForAliasCircle(name, alias); //注冊(cè)alias和name this.aliasMap.put(alias, name); } } }
bean節(jié)點(diǎn)的解析
processBeanDefinition(ele, delegate)實(shí)現(xiàn)如下:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { //解析bean元素,創(chuàng)建BeanDefinitionHolder實(shí)例 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { //完成必須的裝配 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // 進(jìn)行最終的注冊(cè)bean 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)); } }
bean元素的解析和注冊(cè)相對(duì)復(fù)雜,在下一節(jié)中討論。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/76388.html
摘要:在上一篇文章中,分析了容器的創(chuàng)建,加載資源文件,將資源文件讀取為。將文件中的注冊(cè)定義的對(duì)象。在中對(duì)屬性的解析委托給這個(gè)代理類來實(shí)現(xiàn)的。首先,獲取節(jié)點(diǎn)。 在上一篇文章中,分析了ApplicationContext容器的創(chuàng)建,加載資源文件,將資源文件讀取為Document。spring將xml文件中的Bean注冊(cè)spring定義的BeanDefinition對(duì)象。在DefaultBeanD...
摘要:在上一篇文章中,分析了容器的創(chuàng)建,加載資源文件,將資源文件讀取為。將文件中的注冊(cè)定義的對(duì)象。在中對(duì)屬性的解析委托給這個(gè)代理類來實(shí)現(xiàn)的。首先,獲取節(jié)點(diǎn)。 在上一篇文章中,分析了ApplicationContext容器的創(chuàng)建,加載資源文件,將資源文件讀取為Document。spring將xml文件中的Bean注冊(cè)spring定義的BeanDefinition對(duì)象。在DefaultBeanD...
摘要:在的方法中,遍歷每一個(gè)節(jié)點(diǎn),判斷是否為默認(rèn)命名空間中的節(jié)點(diǎn),如果是非默認(rèn)命名空間的,調(diào)用方法進(jìn)行處理。在學(xué)習(xí)自定義標(biāo)簽解析之前,先寫一個(gè)自定義標(biāo)簽的。 在DefaultBeanDefinitionDocumentReader的parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)方法中,遍歷每一...
摘要:在的方法中,遍歷每一個(gè)節(jié)點(diǎn),判斷是否為默認(rèn)命名空間中的節(jié)點(diǎn),如果是非默認(rèn)命名空間的,調(diào)用方法進(jìn)行處理。在學(xué)習(xí)自定義標(biāo)簽解析之前,先寫一個(gè)自定義標(biāo)簽的。 在DefaultBeanDefinitionDocumentReader的parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)方法中,遍歷每一...
摘要:在的方法中,遍歷每一個(gè)節(jié)點(diǎn),判斷是否為默認(rèn)命名空間中的節(jié)點(diǎn),如果是非默認(rèn)命名空間的,調(diào)用方法進(jìn)行處理。在學(xué)習(xí)自定義標(biāo)簽解析之前,先寫一個(gè)自定義標(biāo)簽的。 在DefaultBeanDefinitionDocumentReader的parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)方法中,遍歷每一...
閱讀 1369·2021-10-13 09:39
閱讀 1333·2021-09-23 11:22
閱讀 2243·2019-08-30 14:05
閱讀 1059·2019-08-29 17:03
閱讀 771·2019-08-29 16:24
閱讀 2227·2019-08-29 13:51
閱讀 656·2019-08-29 13:00
閱讀 1291·2019-08-29 11:24