Spring源码解析之BeanDefinition完整装配过程详解

解析构造注入的参数

//解析构造函数的参数
parseConstructorArgElements(ele, bd);

进入其中源码:

	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_ELEMENT
			if (isCandidateElement(node) && nodeNameEquals(node, CONSTRUCTOR_ARG_ELEMENT))
			{
				//解析构造器
				parseConstructorArgElement((Element) node, bd);
			}
		}
	}

解析属性注入的参数

//解析properties子元素
parsePropertyElements(ele, bd);

可以看里面的源码和构造注入基本相同:

	/**
	 * Parse property sub-elements of the given bean element.
	 */
	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);
			}
		}
	}

所以我们能看出来他的核心就在parsePropertyElement,我们要着重看下里面的源代码!

	public void parsePropertyElement(Element ele, BeanDefinition bd)
	{
		//获取name属性
		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
		{
			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();
		}
	}

首先是获取name属性,没有就报错。获取到之后,里面调用parsePropertyValue方法来进行解析:

	//ref是引用另外一个定义好的bean
		boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
		boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
		//ref和value属性不能共存,不然报错!
		if ((hasRefAttribute && hasValueAttribute) ||
				((hasRefAttribute || hasValueAttribute) && subElement != null))
		{
			error(elementName +
					" is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
		}

		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;
		} 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;
		}

我拿了一段核心出来!
首先判断bean元素中有ref属性,他通过RuntimeBeanReference,对需要的属性进行填充!
在这里插入图片描述
在这里插入图片描述
判断是否有value元素TypedStringValue
在这里插入图片描述

	public TypedStringValue(@Nullable String value) {
		setValue(value);
	}

解析qualifier子元素

在这里插入图片描述
进入parseQualifierElement查看源码,其实大致一致!

解析bean name的定义

在这里插入图片描述

if (containingBean != null)
{
	beanName = BeanDefinitionReaderUtils.generateBeanName(
			beanDefinition, this.readerContext.getRegistry(), true);
}

源码:

	public static String generateBeanName(
			BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean)
			throws BeanDefinitionStoreException {

		//获取bean的class名字
		String generatedBeanName = definition.getBeanClassName();
		if (generatedBeanName == null) {//如果bean的名字为空且父元素不为空
			if (definition.getParentName() != null) {
				//那就在父名称后面加个$child
				generatedBeanName = definition.getParentName() + "$child";
			}
			else if (definition.getFactoryBeanName() != null) {//如果bean的名字为空且工厂名称不为空
				//那就在工厂名字后面加个$created
				generatedBeanName = definition.getFactoryBeanName() + "$created";
			}
		}
		if (!StringUtils.hasText(generatedBeanName)) {
			throw new BeanDefinitionStoreException("Unnamed bean definition specifies neither " +
					"'class' nor 'parent' nor 'factory-bean' - can't generate bean name");
		}

		if (isInnerBean) {
			// Inner bean: generate identity hashcode suffix.
			return generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition);
		}

		// Top-level bean: use plain class name with unique suffix if necessary.
		//顶级bean:必要时使用带有唯一后缀的普通类名。
		return uniqueBeanName(generatedBeanName, registry);
	}

上面这一系列完成之后,也就是完成了bean属性的定义!

bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
	public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
			Element ele, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd)
	{

		BeanDefinitionHolder finalDefinition = originalDef;

		// Decorate based on custom attributes first.
		NamedNodeMap attributes = ele.getAttributes();
		//一个是用于对所有的属性进行遍历处理
		for (int i = 0; i < attributes.getLength(); i++)
		{
			Node node = attributes.item(i);
			finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
		}

		// Decorate based on custom nested elements.
		NodeList children = ele.getChildNodes();
		//另一个是对所有的子节点进行处理
		for (int i = 0; i < children.getLength(); i++)
		{
			Node node = children.item(i);
			if (node.getNodeType() == Node.ELEMENT_NODE)
			{
				finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
			}
		}
		return finalDefinition;
	}

注册最终装饰的实例到工厂

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

后面会对立面的源码进行深度剖析!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值