- Web核心-Servlet
- Spring原始碼系列:啟動過程
- Spring原始碼系列:容器重新整理
- Spring原始碼系列:BeanFactory的建立
- Spring原始碼系列:BeanDefinition原始碼解析
- Spring原始碼系列:BeanDefinition載入(上)
- Spring原始碼系列:BeanDefinition載入(中)
- Spring原始碼系列:BeanDefinition載入(下)
上一篇是將Bean的解析註冊流程進行了梳理,對於一些細節問題沒有進行細究,比如說元素屬性值的處理,建構函式的處理等等。本篇就學習記錄一下相關點。
首先來看下是在哪個地方具體生成BeanDefinitiond的。下面是方法請求的順序。
-
- DefaultBeanDefinitionDocumentReader.parseDefaultElement
-
- DefaultBeanDefinitionDocumentReader.processBeanDefinition
-
- BeanDefinitionParserDelegate.parseBeanDefinitionElement
關於元素的解析絕大多數都是在BeanDefinitionParserDelegate及其子類中完成的。OK,來看下parseBeanDefinitionElement這個方法:
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
String className = null;
//在這裡是讀取<bean>的class名字,然後載入到BeanDefinition中,並未做例項化
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
try {
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
//生成BeanDefinition物件
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
//解析當前bean的屬性
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
//設定description資訊
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
//對bean的元素資訊進行解析
parseMetaElements(ele, bd);
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
//解析bean的建構函式設定
parseConstructorArgElements(ele, bd);
//解析property設定
parsePropertyElements(ele, bd);
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
}
//異常1:ClassNotFoundException
catch (ClassNotFoundException ex) {
error("Bean class [" + className + "] not found", ele, ex);
}
//異常2:NoClassDefFoundError
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;
}
複製程式碼
此處我們以解析property為例,看下具體的處理細節:
//解析給定bean元素的屬性子元素。
public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
//獲取子元素節點
NodeList nl = beanEle.getChildNodes();
//遍歷
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
//是否包含property標識
if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
parsePropertyElement((Element) node, bd);
}
}
}
複製程式碼
接著是執行具體property,在parsePropertyElement中完成:
//解析一個property元素。
public void parsePropertyElement(Element ele, BeanDefinition bd) {
//首先獲取到property的名稱
String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
//檢查是否有name
if (!StringUtils.hasLength(propertyName)) {
error("Tag 'property' must have a 'name' attribute", ele);
return;
}
this.parseState.push(new PropertyEntry(propertyName));
try {
//驗證在同一個bean中存在同名的property,存在的話就不解析了,直接返回
if (bd.getPropertyValues().contains(propertyName)) {
error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
return;
}
//解析出property的值
Object val = parsePropertyValue(ele, bd, propertyName);
//封裝成PropertyValue物件
PropertyValue pv = new PropertyValue(propertyName, val);
parseMetaElements(ele, pv);
pv.setSource(extractSource(ele));
bd.getPropertyValues().addPropertyValue(pv);
}
finally {
this.parseState.pop();
}
}
複製程式碼
在parsePropertyValue中,是對所有的property子元素進行具體解析的。我們知道property中除了單值之外,還會包括如:list,set,map,prop等集合元素;這些都會被封裝成對應的Managerd物件。比如:ManagedList等。不同的集合型別頁同樣對應一種解析方法,比如解析list的是使用parseListElement。這些解析都是在BeanDefinitionParserDelegate類中完成的。這個後面我會抽一篇來學習BeanDefinitionParserDelegate這個類。
Bean的載入過程就是這樣通過層層解析來完成的,但是對於目前的Ioc容器來說,僅僅是完成了對Bean物件管理的一些資料準備工作,也就是初始化工作,目前的BeanDefginiton中包含的就是一些靜態的配置資訊,Bean的例項化還沒有進行,這個例項化的過程是在依賴注入時候完成的。