【死磕 Spring】----- IOC 之解析 bean 標籤:解析自定義標籤

前面四篇文章都是分析 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 實例對象。


原文發佈時間爲:2018-09-26
本文作者:Java技術驛站
本文來自雲棲社區合作伙伴“Java技術驛站”,瞭解相關信息可以關注“Java技術驛站”。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章