spring深入學習(六) IOC 之解析 bean 標籤:開啟解析程序
阿新 • • 發佈:2019-02-18
import 標籤解析完畢了,再看 Spring 中最複雜也是最重要的標籤 bean 標籤的解析過程。
在方法 parseDefaultElement()
中,如果遇到標籤 為 bean 則呼叫 processBeanDefinition()
方法進行 bean 標籤解析,如下:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. 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)); } }
整個過程分為四個步驟
- 呼叫
BeanDefinitionParserDelegate.parseBeanDefinitionElement()
進行元素解析,解析過程中如果失敗,返回 null,錯誤由ProblemReporter
處理。如果解析成功則返回 BeanDefinitionHolder 例項 bdHolder。BeanDefinitionHolder 為持有 name 和 alias 的 BeanDefinition。 - 若例項 bdHolder 不為空,則呼叫
BeanDefinitionParserDelegate.decorateBeanDefinitionIfRequired()
- 解析完成後,則呼叫
BeanDefinitionReaderUtils.registerBeanDefinition()
對 bdHolder 進行註冊 - 發出響應事件,通知相關的監聽器,完成 Bean 標籤解析
先看方法 parseBeanDefinitionElement()
,如下:
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) { // 解析 ID 屬性 String id = ele.getAttribute(ID_ATTRIBUTE); // 解析 name 屬性 String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); // 分割 name 屬性 List<String> aliases = new ArrayList<>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } String beanName = id; if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { beanName = aliases.remove(0); if (logger.isDebugEnabled()) { logger.debug("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases"); } } // 檢查 name 的唯一性 if (containingBean == null) { checkNameUniqueness(beanName, aliases, ele); } // 解析 屬性,構造 AbstractBeanDefinition AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { // 如果 beanName 不存在,則根據條件構造一個 beanName if (!StringUtils.hasText(beanName)) { try { if (containingBean != null) { beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this.readerContext.getRegistry(), true); } else { 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 return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null; }
這個方法還沒有對 Bean 標籤進行解析,只是在解析動作之前做了一些功能架構,主要的工作有:
- 解析 id、name 屬性,確定 alias 集合,檢測 beanName 是否唯一
- 呼叫方法
parseBeanDefinitionElement()
對屬性進行解析並封裝成 GenericBeanDefinition 例項 beanDefinition - 根據所獲取的資訊(beanName、aliases、beanDefinition)構造 BeanDefinitionHolder 例項物件並返回。
這裡有必要說下 beanName 的命名規則:如果 id 不為空,則 beanName = id;如果 id 為空,但是 alias 不空,則 beanName 為 alias 的第一個元素,如果兩者都為空,則根據預設規則來設定 beanName。
上面三個步驟第二個步驟為核心方法,它主要承擔解析 Bean 標籤中所有的屬性值。如下:
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, @Nullable BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
String className = null;
// 解析 class 屬性
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
String parent = null;
// 解析 parent 屬性
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
try {
// 建立用於承載屬性的 GenericBeanDefinition 例項
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
// 解析預設 bean 的各種屬性
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
// 提取 description
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
// 解析元資料
parseMetaElements(ele, bd);
// 解析 lookup-method 屬性
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
// 解析 replaced-method 屬性
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
// 解析建構函式引數
parseConstructorArgElements(ele, bd);
// 解析 property 子元素
parsePropertyElements(ele, bd);
// 解析 qualifier 子元素
parseQualifierElements(ele, bd);
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;
}
到這裡,Bean 標籤的所有屬性我們都可以看到其解析的過程,也就說到這裡我們已經解析一個基本可用的 BeanDefinition。