Spring源碼系列:BeanDefinition載入(中)

上一篇是將Bean的解析註冊流程進行了梳理,對於一些細節問題沒有進行細究,好比說元素屬性值的處理,構造函數的處理等等。本篇就學習記錄一下相關點。java

首先來看下是在哪一個地方具體生成BeanDefinitiond的。下面是方法請求的順序。node

    1. DefaultBeanDefinitionDocumentReader.parseDefaultElement
    1. DefaultBeanDefinitionDocumentReader.processBeanDefinition
    1. BeanDefinitionParserDelegate.parseBeanDefinitionElement

關於元素的解析絕大多數都是在BeanDefinitionParserDelegate及其子類中完成的。OK,來看下parseBeanDefinitionElement這個方法:ide

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中完成:post

//解析一個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的實例化尚未進行,這個實例化的過程是在依賴注入時候完成的。this

相關文章
相關標籤/搜索