Spring源码解析十

上一篇中,我们已经找到了默认标签解析入口,也就是方法parseDefaultElement,下面我们接着从这个方法分析:
在这里插入图片描述
我们到方法parseDefaultElement中,看下Spring是如何解析默认标签的。
在这里插入图片描述
可以看到,解析xml标签的结构还是比较清晰的,我们先看下这几个常量表示的是什么?
在这里插入图片描述
这些不就是我们的标签名称吗,比如beans、import、alias。
因为我们平时使用alias 和import 标签都比较少,所以我们就不重点分析它们了,我们还是看比较核心的bean标签的解析。
在这里插入图片描述
我们跳到processBeanDefinition方法中:
在这里插入图片描述
可以看到 在这个方法中,主要是分为两个步骤:
1、解析bean的标签元素
2、将解析的bean注册到spring容器中
我们先看解析bean的标签元素,这个解析操作还是委托给BeanDefinitionParserDelegate来帮忙的。那么这个BeanDefinitionParserDelegate对象会如何解析默认标签bean呢?我们到这个delegate.pareseBeanDefinitionElement方法中去看:
在这里插入图片描述
我们继续跟到方法parseBeanDefinitionElement方法中看下:

@Nullable
	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
		// 1、获取bean标签中,属性id和name的值
		String id = ele.getAttribute(ID_ATTRIBUTE);
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

		// 2、将属性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));
		}

		//3、如果属性id的值为空,那就获取aliases 集合中的第一个value值,作为bean的名称
		String beanName = id;
		if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
			beanName = aliases.remove(0);
			if (logger.isTraceEnabled()) {
				logger.trace("No XML 'id' specified - using '" + beanName +
						"' as bean name and " + aliases + " as aliases");
			}
		}

		if (containingBean == null) {
			checkNameUniqueness(beanName, aliases, ele);
		}
		
		//4、开始深入的解析bean标签,将解析的结果封装为AbstractBeanDefinition
		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
		if (beanDefinition != null) {
			// beanName 不等于空,就直接跳过
			if (!StringUtils.hasText(beanName)) {
				try {
					if (containingBean != null) {
						beanName = BeanDefinitionReaderUtils.generateBeanName(
								beanDefinition, this.readerContext.getRegistry(), true);
					}
					else {
						beanName = this.readerContext.generateBeanName(beanDefinition);
						// Register an alias for the plain bean class name, if still possible,
						// if the generator returned the class name plus a suffix.
						// This is expected for Spring 1.2/2.0 backwards compatibility.
						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()) {
						logger.trace("Neither XML 'id' nor 'name' specified - " +
								"using generated bean name [" + beanName + "]");
					}
				}
				catch (Exception ex) {
					error(ex.getMessage(), ele);
					return null;
				}
			}
			// 5、根据解析到的beanDefinition、beanName和aliases 创建一个BeanDefinitionHolder
			String[] aliasesArray = StringUtils.toStringArray(aliases);
			return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
		}

		return null;
	}

里面bean标签的解析还是挺复杂的,接下来我们就要一步一步的分析下bean标签解析的各个环节。

在这里插入图片描述
我们先看这两行代码,首先是获取标签中的属性id值,以及属性name的nameAttr,我们在bean标签中都会配置属性id的。
在这里插入图片描述
接下来,如果name属性值nameAttr不为空的话,通过方法StringUtils.tokenizeToStringArray进行分割:
在这里插入图片描述
其中,MULTI_VALUE_ATTRIBUTE_DELIMITERS的值为",;",也就是说在配置属性name的值时,可以通过"," 或";" 作为分隔符,配置多个name属性值。比如name属性值为 “user,users”,分割后可以得到nameAttr数组为[“user”,“users”],然后将数组添加到aliases集合中。
那aliases集合有什么作用呢?我们接着继续看:
在这里插入图片描述
可以看到,当id属性值为空时,就会从aliases集合中调用方法remove(0),来获取第一个元素作为beanName的值。

上面的这些都是bean标签解析前的一些准备工作。
我们继续往下面看:
在这里插入图片描述
通过这个方法名称parseBeanDefinitionElement 我们就应该知道,bean标签解析的关键方法就是它了。我们在进到方法parseBeanDefinitionElement 中看下:

/**
	 * Parse the bean definition itself, without regard to name or aliases. May return
	 * {@code null} if problems occurred during the parsing of the bean definition.
	 */
	@Nullable
	public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, @Nullable BeanDefinition containingBean) {

		this.parseState.push(new BeanEntry(beanName));

		String className = null;
		// 1、 如果bean标签存在class属性,获取class 属性值
		if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
			className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
		}
		String parent = null;
		// 2、如果bean标签存在parent属性,获取parent属性值
		if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
			parent = ele.getAttribute(PARENT_ATTRIBUTE);
		}

		try {
			// 3、通过属性class 和 parent值,创建AbstractBeanDefinition
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);
			
			// 4、解析bean标签中的各种其他属性,并封装到AbstractBeanDefinition中
			parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
			bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

			//5、解析bean标签下的各种子标签元素,解析结果封装到AbstractBeanDefinition中
			
			// 解析bean的子标签元素 meta
			parseMetaElements(ele, bd);
			// 解析bean的子标签元素, lookup-method
			parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
			// 解析bean的子标签元素 replaced-method
			parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
			
			//解析 bean的子标签元素 constructor-arg
			parseConstructorArgElements(ele, bd);
			// 解析bean的子标签元素 property
			parsePropertyElements(ele, bd);
			// 解析bean的子标签元素 qualifier
			parseQualifierElements(ele, bd);

			bd.setResource(this.readerContext.getResource());
			bd.setSource(extractSource(ele));

			// 返回bd对象
			return bd;
		}
		catch (ClassNotFoundException ex) {
			error("Bean class [" + className + "] not found", ele, ex);
		}
		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;
	}

可以看到,这个方法中还是继续解析bean标签中的属性,分别获取属性class的值className,以及属性parent的值parent,然后将这两个属性的值传入到方法createBeanDefinition中,创建一个AbstractBeanDefinition类型的对象bd,最后把解析bean标签的属性值都封装到AbstractBeanDefinition里面。

那么在这个createBeanDefinition方法中到底做了什么呢?我们们知道AbstractBeanDefinition是一个抽象类是无法创建对象的。我们继续进去看下:
在这里插入图片描述
可以看到,在createBeanDefinition 方法中,BeanDefinitionReaderUtils又调用方法createBeanDefinition 进一步处理,继续往下看:
在这里插入图片描述
可以看到,实际上是创建的BeanDefinition为GenericBeanDefinition,并且将parent和class 属性值设置到GenericBeanDefinition之后并返回。
那这个GenericBeanDefinitio这个类是什么呢?我们都知道bean在Spring容器中都是以BeanDefinition的形式存在的,也就是说我们在xml中配置的一个bean标签,在Spring容器中存在的形式就是BeanDefinition。其实不但是通过xml配置的bean,就是我们通过注解形式配置的bean,最终都会生成BeanDefinition 。
但是这个BeanDefinition 只是一个接口而已,Spring在解析bean标签时会为我们创建一个GenericBeanDefinition出来,用于存放bean标签解析出来各种信息,我们在下一篇中将会介绍GenericBeanDefinition这个类。

Spring流程图:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

youngerone123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值