歡迎光臨
每天分享高質量文章

【死磕 Spring】—– IOC 之解析 bean 標簽:解析自定義標簽

點擊上方“Java技術驛站”,選擇“置頂公眾號”。

有內涵、有價值的文章第一時間送達!

精品專欄

 

前面四篇文章都是分析 Bean 預設標簽的解析過程,包括基本屬性、六個子元素(meta、lookup-method、replaced-method、constructor-arg、property、qualifier),涉及內容較多,拆分成了四篇文章,導致我們已經忘記從哪裡出發的了,勿忘初心

processBeanDefinition() 負責 Bean 標簽的解析,在解析過程中首先呼叫BeanDefinitionParserDelegate.parseBeanDefinitionElement() 完成預設標簽的解析,如果解析成功(傳回的 bdHolder != null ),則首先呼叫 BeanDefinitionParserDelegate.decorateBeanDefinitionIfRequired() 完成自定義標簽元素解析,前面四篇文章已經分析了預設標簽的解析,所以這篇文章分析自定義標簽的解析。

  1.    public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) {

  2.        return decorateBeanDefinitionIfRequired(ele, definitionHolder, null);

  3.    }

呼叫 decorateBeanDefinitionIfRequired() :

  1.    public BeanDefinitionHolder decorateBeanDefinitionIfRequired(

  2.            Element ele, BeanDefinitionHolder definitionHolder, @Nullable BeanDefinition containingBd) {

  3.        BeanDefinitionHolder finalDefinition = definitionHolder;

  4.        // 遍歷節點,查看是否有適用於裝飾的屬性

  5.        NamedNodeMap attributes = ele.getAttributes();

  6.        for (int i = 0; i < attributes.getLength(); i++) {

  7.            Node node = attributes.item(i);

  8.            finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);

  9.        }

  10.        // 遍歷子節點,查看是否有適用於修飾的子元素

  11.        NodeList children = ele.getChildNodes();

  12.        for (int i = 0; i < children.getLength(); i++) {

  13.            Node node = children.item(i);

  14.            if (node.getNodeType() == Node.ELEMENT_NODE) {

  15.                finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);

  16.            }

  17.        }

  18.        return finalDefinition;

  19.    }

遍歷節點(子節點),呼叫 decorateIfRequired() 裝飾節點(子節點)。

  1.    public BeanDefinitionHolder decorateIfRequired(

  2.            Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {

  3.        // 獲取自定義標簽的命名空間

  4.        String namespaceUri = getNamespaceURI(node);

  5.        // 過濾掉預設命名標簽

  6.        if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {

  7.            // 獲取相應的處理器

  8.            NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);

  9.            if (handler != null) {

  10.                // 進行裝飾處理

  11.                BeanDefinitionHolder decorated =

  12.                        handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));

  13.                if (decorated != null) {

  14.                    return decorated;

  15.                }

  16.            }

  17.            else if (namespaceUri.startsWith("http://www.springframework.org/")) {

  18.                error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);

  19.            }

  20.            else {

  21.                if (logger.isDebugEnabled()) {

  22.                    logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");

  23.                }

  24.            }

  25.        }

  26.        return originalDef;

  27.    }

首先獲取自定義標簽的命名空間,如果不是預設的命名空間則根據該命名空間獲取相應的處理器,最後呼叫處理器的 decorate() 進行裝飾處理。具體的裝飾過程這裡不進行講述,在後面分析自定義標簽時會做詳細說明。

至此,Bean 的解析過程已經全部完成了,下麵做一個簡要的總結。

解析 BeanDefinition 的入口在 DefaultBeanDefinitionDocumentReader.parseBeanDefinitions() 。該方法會根據命令空間來判斷標簽是預設標簽還是自定義標簽,其中預設標簽由 parseDefaultElement() 實現,自定義標簽由 parseCustomElement() 實現。在預設標簽解析中,會根據標簽名稱的不同進行 import 、alias 、bean 、beans 四大標簽進行處理,其中 bean 標簽的解析為核心,它由 processBeanDefinition() 方法實現。 processBeanDefinition() 開始進入解析核心工作,分為三步:

  1. 解析預設標簽: BeanDefinitionParserDelegate.parseBeanDefinitionElement()

  2. 解析預設標簽下的自定義標簽: BeanDefinitionParserDelegate.decorateBeanDefinitionIfRequired()

  3. 註冊解析的 BeanDefinition: BeanDefinitionReaderUtils.registerBeanDefinition

在預設標簽解析過程中,核心工作由 parseBeanDefinitionElement() 方法實現,該方法會依次解析 Bean 標簽的屬性、各個子元素,解析完成後傳回一個 GenericBeanDefinition 實體物件。

【死磕 Spring】—– IOC 之解析 bean 標簽:meta、lookup-method、replace-method)

【死磕 Spring】----- IOC 之解析 bean 標簽:開啟解析行程

【死磕 Spring】----- IOC 之解析 bean 標簽:BeanDefinition

【死磕 Spring】----- IOC 之 獲取 Document 物件

【死磕 Spring】----- IOC 之 註冊 BeanDefinition

【死磕 Spring】----- IOC 之 獲取驗證模型

【死磕 Spring】----- IOC 之 Spring 統一資源加載策略

【死磕 Spring】----- IOC 之深入理解 Spring IoC

END

我是 Java 技術驛站,感謝有你

赞(0)

分享創造快樂

© 2021 知識星球   网站地图