Spring源码解析(三)----解析dom对象,返回bd实例

GenericBeanDefinition的关系结构图

GenericBeanDefinition
GenericBeanDefinition用于承载解析出来的Bean信息

DefaultBeanDefinitionParserDelegate

parseBeanDefinitionElement:解析bean标签,并以BeanDefinitionHolder对象返回

	@Nullable
	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
		return parseBeanDefinitionElement(ele, null);
	}

parseBeanDefinitionElement:

1、提取元素中的id和name属性
2、进一步解析其他所有属性,并封装到GenericBeanDefinition中
3、如果没有beanName则使用默认规则生成一个
4、将获取的信息封装到GenericBeanDefinition中返回

	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
		//获取id和name
		String id = ele.getAttribute(ID_ATTRIBUTE);
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
		//别名集合,以,或者;分割所有name,存进aliases
		List<String> aliases = new ArrayList<>();
		if (StringUtils.hasLength(nameAttr)) {
			String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			aliases.addAll(Arrays.asList(nameArr));
		}
		//bean名字默认为id,若没有id则使用name值中的第一个值
		String beanName = id;
		if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
			beanName = aliases.remove(0);
			if (logger.isTraceEnabled()) {}
		}
		待定-------------------------------------------------
		if (containingBean == null) {
			checkNameUniqueness(beanName, aliases, ele);
		}
		//解析其他属性和子标签,并将其与AbstractBeanDefinition的属性值对应 
		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
		//
		if (beanDefinition != null) {
			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.isTraceEnabled()) {}
				}
				catch (Exception ex) {
				error(ex.getMessage(), ele);return null;
				}
			}
			String[] aliasesArray = StringUtils.toStringArray(aliases);
			return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
		}
		return null;
	}

parseBeanDefinitionElement

解析标签所有子标签和属性,将属性值放进AbstractBeanDefinition 返回

	public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, @Nullable BeanDefinition containingBean) {
		//ParseState有一个属性ArrayDeque<Entry> state;Entry说白了就是给String类型包了一层,然后叫BeanEntry
		this.parseState.push(new BeanEntry(beanName));
		//获取className和parent
		String className = null;
		if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
			className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
		}
		String parent = null;
		if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
			parent = ele.getAttribute(PARENT_ATTRIBUTE);
		}

		try {
			//见内部代码2.1:设置了beanClass和parentName属性,对于beanClass,若readerContext的classLoader不为空,则直接将Class实例加载给beanClass,否则直接设置一个className,即类的全限定名
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);
			//见内部代码2.2;解析标签的所有属性;该方法返回了bd,但bd也作为参数传进去了,所以没使用返回值
			parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
			//查看该bean里有无子标签<description>,有则将其内容取出,设置
			bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
			//见内部代码2.3:
			parseMetaElements(ele, bd);
			//见内部代码2.4;
			parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
			//见内部代码2.5;
			parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
			//见内部代码2.6:
			parseConstructorArgElements(ele, bd);
			parsePropertyElements(ele, bd);
			parseQualifierElements(ele, bd);

			bd.setResource(this.readerContext.getResource());
			bd.setSource(extractSource(ele));
			return bd;
		}
		catch (ClassNotFoundException ex) {}
		finally {
			this.parseState.pop();
		}
		return null;
	}

内部代码2.1:创建并初始化AbstractBeanDefinition

设置parentName和beanClass属性,使用Object beanClass属性接收String类型的className或者Class类型的已加载的类

	protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
			throws ClassNotFoundException {

		return BeanDefinitionReaderUtils.createBeanDefinition(
				parentName, className, this.readerContext.getBeanClassLoader());
	}
---------BeanDefinitionReaderUtils----------------------
	public static AbstractBeanDefinition createBeanDefinition(
			@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {
		//该构造器继续调用super,最终给2个属性赋值null------》等于什么都没做
		GenericBeanDefinition bd = new GenericBeanDefinition();
		//设置parent属性
		bd.setParentName(parentName);
		//使用Object beanClass属性接收String类型的className或者Class类型的已加载的类
		if (className != null) {
			if (classLoader != null) {
				bd.setBeanClass(ClassUtils.forName(className, classLoader));
			}
			else {
				bd.setBeanClassName(className);
			}
		}
		return bd;
	}

内部代码2.2:parseBeanDefinitionAttributes:解析标签的所有属性

	public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
			@Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {
	}

内部代码2.3:parseMetaElements:解析子元素meta

首先先看下meta的作用:可以使用BeanDifinition的getAttribute(key)方法得到value值

    <bean id="myBean" class="com.example.pojo.MyBean" init-method=" ">
        <meta key="myBeanMetaKey" value="myBeanMetaValue" />
    </bean>

解析meta属性:

	public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) {
		NodeList nl = ele.getChildNodes();
		for (int i = 0; i < nl.getLength(); i++) {
			Node node = nl.item(i);
			if (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT)) {
				Element metaElement = (Element) node;
				String key = metaElement.getAttribute(KEY_ATTRIBUTE);
				String value = metaElement.getAttribute(VALUE_ATTRIBUTE);
				BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);
				attribute.setSource(extractSource(metaElement));
				attributeAccessor.addMetadataAttribute(attribute);
			}
		}
	}

内部代码2.4:parseLookupOverrideSubElements

获取<bean>下的<lookup-method>
<lookup-method\ name=“methodName” bean=“beanRef” />
:可以给没有实现类的抽象方法指定返回的实例对象

	public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) {
		NodeList nl = beanEle.getChildNodes();
		for (int i = 0; i < nl.getLength(); i++) {
			Node node = nl.item(i);
			if (isCandidateElement(node) && nodeNameEquals(node, LOOKUP_METHOD_ELEMENT)) {
				Element ele = (Element) node;
				String methodName = ele.getAttribute(NAME_ATTRIBUTE);
				String beanRef = ele.getAttribute(BEAN_ELEMENT);
				LookupOverride override = new LookupOverride(methodName, beanRef);
				override.setSource(extractSource(ele));
				overrides.addOverride(override);
			}
		}
	}

内部代码2.6:解析ConstructorArg标签

遍历该标签下所有ConstructorArg标签,挨个解析

1、parseConstructorArgElements

	//对每个constructor-arg标签进行解析
	public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
		NodeList nl = beanEle.getChildNodes();
		for (int i = 0; i < nl.getLength(); i++) {
			Node node = nl.item(i);
			if (isCandidateElement(node) && nodeNameEquals(node, CONSTRUCTOR_ARG_ELEMENT)) {
				parseConstructorArgElement((Element) node, bd);
			}
		}
	}

2、parseConstructorArgElement

1、获取index,type,name属性
2.1、如果配置了index属性,则

  • 解析constructor-arg子标签
  • 使用ConstructorArgumentValues.ValueHolder封装解析结果
  • 将type、name和index封装进ConstructorArgumentValues.ValueHolder并添加至ConstructorArgumentValues的indexedArgumentValues属性中
  • private final Map<Integer, ValueHolder> indexedArgumentValues = new LinkedHashMap<>();

2.2、若没有配置index属性

  • 解析constructor-arg子标签
  • 使用ConstructorArgumentValues.ValueHolder封装解析结果
  • 将type、name和index封装进ConstructorArgumentValues.ValueHolder并添加至ConstructorArgumentValues的 genericArgumentValues属性中
  • private final List<ValueHolder> genericArgumentValues = new ArrayList<>();
	//
	public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
		String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);
		String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
		
		//若存在index属性,
		if (StringUtils.hasLength(indexAttr)) {
			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));
						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 {
							bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder);
						}
					}
					finally {
						this.parseState.pop();
					}
				}
			}
			catch (NumberFormatException ex) {
				error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele);
			}
		}
		else {
			try {
				this.parseState.push(new ConstructorArgumentEntry());
				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));
				bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
			}
			finally {
				this.parseState.pop();
			}
		}
	}

3、parsePropertyValue

解析构造器标签值

	@Nullable
	public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) {
		String elementName = (propertyName != null ?
				"<property> element for property '" + propertyName + "'" :
				"<constructor-arg> element");

		// 获取该标签的所有子标签
		NodeList nl = ele.getChildNodes();
		//子标签中除了<meta>和<description>,其余的只能存在一个,否则报错,并将仅有一个赋值给subElement
		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)) {
				// Child element is what we're looking for.
				if (subElement != null) {
					error(elementName + " must not contain more than one sub-element", ele);
				}
				else {
					subElement = (Element) node;
				}
			}
		}
		//<construct-arg>标签的ref和value属性同时存在,或者二者存一并且subElement不为空,则报错
		boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
		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实例中并标明来源,返回
		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值和ref值处理类似,只不过存在了TypedStringValue实例
		else if (hasValueAttribute) {
			TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
			//标明来源
			valueHolder.setSource(extractSource(ele));
			return valueHolder;
		}
		//对子标签进行解析
		else if (subElement != null) {
			return parsePropertySubElement(subElement, bd);
		}
		else {
			// Neither child element nor "ref" or "value" attribute found.
			error(elementName + " must specify a ref or value", ele);
			return null;
		}
	}

其他方法也是类似,就不逐一分析了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值