IOC實現之XML元素解析過程(四)

接着上篇文章我們繼續來做構造器配置與屬性配置的解析過程分析;

我們先來看看BeanDefinitionParserDelegate是怎麼來解析構造屬性配置的;

        public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
		//拿到子元素集合
		NodeList nl = beanEle.getChildNodes();
		for (int i = 0; i < nl.getLength(); i++) {
			Node node = nl.item(i);
			//如果子元素是constructor-arg的話
			if (isCandidateElement(node) && nodeNameEquals(node, CONSTRUCTOR_ARG_ELEMENT)) {
				parseConstructorArgElement((Element) node, bd);
			}
		}
	}
	
	public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
		String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);//拿到配置index的值
		String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);//拿到配置type的值
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);//拿到配置的name的值
		try {
			int index = Integer.parseInt(indexAttr);
			if (index < 0) {
				error("'index' cannot be lower than 0", ele);
			}
			else {
				try {
					this.parseState.push(new ConstructorArgumentEntry(index));
					
					//拿到該元素的值,對於我們的配置
					//<constructor-arg index="0" name="color" value="黃色"/>
					//在這裏,我們會得到一個TypedStringValue,它的屬性value值爲"黃色"
					Object value = parsePropertyValue(ele, bd, null);
					ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
					if (StringUtils.hasLength(typeAttr)) {
						valueHolder.setType(typeAttr);
					}
					if (StringUtils.hasLength(nameAttr)) {
						valueHolder.setName(nameAttr);
					}
					valueHolder.setSource(extractSource(ele));
					if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {
						error("Ambiguous constructor-arg entries for index " + index, ele);
					}
					else {
						//將對構造器的xml配置解析後而轉換成的valueHolder對象存入bd中,爲後面的bean的實例化操作提供支持
						//在內部,bd將採用constructorArgumentValues屬性的Map<Integer, ValueHolder> indexedArgumentValues 屬性來存放valueHolder
						bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder);
					}
				}
				finally {
					this.parseState.pop();
				}
			}
		}
		catch (NumberFormatException ex) {
			error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele);
		}	
	}
	
	//解析某個元素並返回配置的值
	public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
		String elementName = (propertyName != null) ?
						"<property> element for property '" + propertyName + "'" :
						"<constructor-arg> element";
		NodeList nl = ele.getChildNodes();
		//拿到property下的子元素,也就是list,set,map...等配置
		Element subElement = null;
		for (int i = 0; i < nl.getLength(); i++) {
			Node node = nl.item(i);
			if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
					!nodeNameEquals(node, META_ELEMENT)) {
				if (subElement != null) {
					error(elementName + " must not contain more than one sub-element", ele);
				}
				else {
					subElement = (Element) node;
				}
			}
		}
		//是否配置了ref
		boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
		//是否配置了value
		boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
		//如果兩個都配置了,就拋出異常
		if ((hasRefAttribute && hasValueAttribute) ||
				((hasRefAttribute || hasValueAttribute) && subElement != null)) {
			error(elementName +
					" is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
		}
		
		//如果配置了ref,則生成一個RuntimeBeanReference對象,它代表着對另一個bean的依賴
		if (hasRefAttribute) {
			String refName = ele.getAttribute(REF_ATTRIBUTE);
			if (!StringUtils.hasText(refName)) {
				error(elementName + " contains empty 'ref' attribute", ele);
			}
			RuntimeBeanReference ref = new RuntimeBeanReference(refName);
			ref.setSource(extractSource(ele));
			return ref;
		}
		//如果配置了value,則生成一個TypedStringValue,它代表着普通的對象屬性值
		else if (hasValueAttribute) {
			TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
			valueHolder.setSource(extractSource(ele));
			return valueHolder;
		}
		else if (subElement != null) {
			//如果有子元素,則繼續對propertiy的子元素進行解析
			return parsePropertySubElement(subElement, bd);
		}
		else {
			error(elementName + " must specify a ref or value", ele);
			return null;
		}
	}
	

        //對properts下的子元素配置進行解析,在解析pants時不會進入這個方法,而person這個bean因爲我們配置了girls這個list屬性,所以會進入
	public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {
		if (!isDefaultNamespace(ele)) {
			return parseNestedCustomElement(ele, bd);
		}
		else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
			BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
			if (nestedBd != null) {
				nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
			}
			return nestedBd;
		}
		//如果是ref...
		else if (nodeNameEquals(ele, REF_ELEMENT)) {
			String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
			boolean toParent = false;
			if (!StringUtils.hasLength(refName)) {
				refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE);
				if (!StringUtils.hasLength(refName)) {
					refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);
					toParent = true;
					if (!StringUtils.hasLength(refName)) {
						error("'bean', 'local' or 'parent' is required for <ref> element", ele);
						return null;
					}
				}
			}
			if (!StringUtils.hasText(refName)) {
				error("<ref> element contains empty target attribute", ele);
				return null;
			}
			RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
			ref.setSource(extractSource(ele));
			return ref;
		}
		else if (nodeNameEquals(ele, IDREF_ELEMENT)) {
			return parseIdRefElement(ele);
		}
		else if (nodeNameEquals(ele, VALUE_ELEMENT)) {
			return parseValueElement(ele, defaultValueType);
		}
		else if (nodeNameEquals(ele, NULL_ELEMENT)) {
			TypedStringValue nullHolder = new TypedStringValue(null);
			nullHolder.setSource(extractSource(ele));
			return nullHolder;
		}
		else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {
			return parseArrayElement(ele, bd);
		}
		//如果是list
		else if (nodeNameEquals(ele, LIST_ELEMENT)) {
			//我們配置的是list,進入這個方法去看看
			return parseListElement(ele, bd);
		}
		//如果是set
		else if (nodeNameEquals(ele, SET_ELEMENT)) {
			return parseSetElement(ele, bd);
		}
		//如果是map
		else if (nodeNameEquals(ele, MAP_ELEMENT)) {
			return parseMapElement(ele, bd);
		}
		else if (nodeNameEquals(ele, PROPS_ELEMENT)) {
			return parsePropsElement(ele);
		}
		else {
			error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
			return null;
		}
	}
	
	//解析list配置
	public List<Object> parseListElement(Element collectionEle, BeanDefinition bd) {
		String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE);
		NodeList nl = collectionEle.getChildNodes();
		//使用ManagedList集合來存放解析後的記錄,而每一條記錄被解析後實際上也是生成上面的TypedStringValue對象!
		ManagedList<Object> target = new ManagedList<Object>(nl.getLength());
		target.setSource(extractSource(collectionEle));
		target.setElementTypeName(defaultElementType);
		target.setMergeEnabled(parseMergeAttribute(collectionEle));
		//填充集合
		parseCollectionElements(nl, target, bd, defaultElementType);
		return target;
	}
	//遍歷子元素,取出每一條記錄進行解析,最終放入集合中;
	protected void parseCollectionElements(
			NodeList elementNodes, Collection<Object> target, BeanDefinition bd, String defaultElementType) {
		for (int i = 0; i < elementNodes.getLength(); i++) {
			Node node = elementNodes.item(i);
			if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT)) {
				target.add(parsePropertySubElement((Element) node, bd, defaultElementType));
			}
		}
	}

OK,現在,我們配置的兩個bean已經解析完成且根據配置元素構建好了BeanDefinition,這個過程看似代碼很多而實際上也是很簡單的,

BeanDefinitionParserDelegate先是在parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) 方法中創建一個GenericBeanDefinition,創建好後調用多個方法來填充GenericBeanDefinition的屬性值,比如調用parseConstructorArgElements()來解析構造配置並將解析後的值轉換爲constructorArgumentValues屬性的indexedArgumentValues屬性中保存起來;把對property的解析結果則會放入propertyValues屬性的List<PropertyValue> propertyValueList之中,代碼如下:

	public void parsePropertyElement(Element ele, BeanDefinition bd) {
		String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
		if (!StringUtils.hasLength(propertyName)) {
			error("Tag 'property' must have a 'name' attribute", ele);
			return;
		}
		this.parseState.push(new PropertyEntry(propertyName));
		try {
			if (bd.getPropertyValues().contains(propertyName)) {
				error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
				return;
			}
			Object val = parsePropertyValue(ele, bd, propertyName);
			//看這裏
			PropertyValue pv = new PropertyValue(propertyName, val);
			parseMetaElements(ele, pv);
			pv.setSource(extractSource(ele));
			bd.getPropertyValues().addPropertyValue(pv);
		}
		finally {
			this.parseState.pop();
		}
	}

BeanDefinition配置好後,BeanDefinitionParserDelegate類將創建一個BeanDefinitionHolder類且返回給DefaultBeanDefinitionDocumentReader,BeanDefinitionHolder這個類就是對BeanDefinition的一層包裝而已;

回到我們的DefaultBeanDefinitionDocumentReader的processBeanDefinition方法之中,我們來看看拿到BeanDefinitionHolder後接下來要做什麼;

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				//調用工具類註冊這個bean!getRegistry()將返回當前beanFactory,也就是DefaultListableBeanFactory
				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));
		}
	}
進入到DefaultListableBeanFactory類的registerBeanDefinition()中去看看;

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

		Assert.hasText(beanName, "Bean name must not be empty");
		Assert.notNull(beanDefinition, "BeanDefinition must not be null");

		if (beanDefinition instanceof AbstractBeanDefinition) {
			try {
				((AbstractBeanDefinition) beanDefinition).validate();
			}
			catch (BeanDefinitionValidationException ex) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Validation of bean definition failed", ex);
			}
		}

		BeanDefinition oldBeanDefinition;
		
		//如果已經存在這個名稱代表的bean,則拋出異常
		oldBeanDefinition = this.beanDefinitionMap.get(beanName);
		if (oldBeanDefinition != null) {
			if (!isAllowBeanDefinitionOverriding()) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
						"': There is already [" + oldBeanDefinition + "] bound.");
			}
			else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
				// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
				if (this.logger.isWarnEnabled()) {
					this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
							"' with a framework-generated bean definition: replacing [" +
							oldBeanDefinition + "] with [" + beanDefinition + "]");
				}
			}
			else {
				if (this.logger.isInfoEnabled()) {
					this.logger.info("Overriding bean definition for bean '" + beanName +
							"': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
				}
			}
		}
		else {
			this.beanDefinitionNames.add(beanName);
			this.manualSingletonNames.remove(beanName);
			this.frozenBeanDefinitionNames = null;
		}
		//我們看到,spring在beanFactory內部就是用一個map來管理beanDefinition的
		this.beanDefinitionMap.put(beanName, beanDefinition);

		if (oldBeanDefinition != null || containsSingleton(beanName)) {
			resetBeanDefinition(beanName);
		}
	}

現在,我們的BeanDefinition已經註冊到BeanFactory容器中去了,它被保存在了一個map集合中,整個IOC容器的資源定位,解析,bean註冊過程到這裏就結束了,只是,我們的Bean到現在都還沒有看到影子,說來說去一直圍繞着BeanDefition類在打轉,那我們的Bean是在什麼時候纔會被實例化呢? 答案是第一次使用這個Bean的時候!而spring去實例化Bean時,需要去根據名稱或者類型去上面的map集合中拿到BeanDefinition,然後再取出我們上面設置好的各種屬性值,再通過反射生成對應的Bean實例!在下篇文章中,我們就來分析實例化Bean的過程;

最後,結合上一篇文章,我們來畫一個時序圖幫助我們理解下資源解析和beanDefinition註冊的方法調用過程;


`



發佈了48 篇原創文章 · 獲贊 5 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章