前面四篇文章都是分析 Bean 預設标簽的解析過程,包括基本屬性、六個子元素(meta、lookup-method、replaced-method、constructor-arg、property、qualifier),涉及内容較多,拆分成了四篇文章,導緻我們已經忘記從哪裡出發的了,勿忘初心。 processBeanDefinition() BeanDefinitionParserDelegate.parseBeanDefinitionElement() BeanDefinitionParserDelegate.decorateBeanDefinitionIfRequired()
負責 Bean 标簽的解析,在解析過程中首先調用
完成預設标簽的解析,如果解析成功(傳回的 bdHolder != null ),則首先調用
完成自定義标簽元素解析,前面四篇文章已經分析了預設标簽的解析,是以這篇文章分析自定義标簽的解析。
-
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) {
-
return decorateBeanDefinitionIfRequired(ele, definitionHolder, null);
-
}
調用
decorateBeanDefinitionIfRequired()
:
-
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
-
Element ele, BeanDefinitionHolder definitionHolder, @Nullable BeanDefinition containingBd) {
-
BeanDefinitionHolder finalDefinition = definitionHolder;
-
// 周遊節點,檢視是否有适用于裝飾的屬性
-
NamedNodeMap attributes = ele.getAttributes();
-
for (int i = 0; i < attributes.getLength(); i++) {
-
Node node = attributes.item(i);
-
finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
-
}
-
// 周遊子節點,檢視是否有适用于修飾的子元素
-
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;
-
}
周遊節點(子節點),調用
decorateIfRequired()
裝飾節點(子節點)。
-
public BeanDefinitionHolder decorateIfRequired(
-
Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
-
// 擷取自定義标簽的命名空間
-
String namespaceUri = getNamespaceURI(node);
-
// 過濾掉預設命名标簽
-
if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
-
// 擷取相應的處理器
-
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
-
if (handler != null) {
-
// 進行裝飾處理
-
BeanDefinitionHolder decorated =
-
handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
-
if (decorated != null) {
-
return decorated;
-
}
-
}
-
else if (namespaceUri.startsWith("http://www.springframework.org/")) {
-
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
-
}
-
else {
-
if (logger.isDebugEnabled()) {
-
logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
-
}
-
}
-
}
-
return originalDef;
-
}
首先擷取自定義标簽的命名空間,如果不是預設的命名空間則根據該命名空間擷取相應的處理器,最後調用處理器的
decorate()
進行裝飾處理。具體的裝飾過程這裡不進行講述,在後面分析自定義标簽時會做詳細說明。
至此,Bean 的解析過程已經全部完成了,下面做一個簡要的總結。
解析 BeanDefinition 的入口在
DefaultBeanDefinitionDocumentReader.parseBeanDefinitions()
。該方法會根據指令空間來判斷标簽是預設标簽還是自定義标簽,其中預設标簽由
parseDefaultElement()
實作,自定義标簽由
parseCustomElement()
實作。在預設标簽解析中,會根據标簽名稱的不同進行 import 、alias 、bean 、beans 四大标簽進行處理,其中 bean 标簽的解析為核心,它由
processBeanDefinition()
方法實作。
processBeanDefinition()
開始進入解析核心工作,分為三步:
- 解析預設标簽:
BeanDefinitionParserDelegate.parseBeanDefinitionElement()
- 解析預設标簽下的自定義标簽:
BeanDefinitionParserDelegate.decorateBeanDefinitionIfRequired()
- 注冊解析的 BeanDefinition:
BeanDefinitionReaderUtils.registerBeanDefinition
在預設标簽解析過程中,核心工作由
parseBeanDefinitionElement()
方法實作,該方法會依次解析 Bean 标簽的屬性、各個子元素,解析完成後傳回一個 GenericBeanDefinition 執行個體對象。
原文釋出時間為:2018-09-26
本文作者:Java技術驿站
本文來自雲栖社群合作夥伴“
Java技術驿站”,了解相關資訊可以關注“
”。