spring源码分析——默认标签的解析

 

 

上一节spring源码分析,看到spring将xml文件封装成了Document对象,然后委托给BeanDefinitionDocumentReader来解析,从parseBeanDefinitions这个方法开始看,

spring源码分析——默认标签的解析

 

一:解析默认元素bean

  1:解析的流程

 spring源码分析——默认标签的解析

 

 

 看一下delegate如何解析bean元素:

spring源码分析——默认标签的解析

 

 

 

 

	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
		// bean元素的属性 id、name(别名,可以配置多个 以,;分隔)
		String id = ele.getAttribute(ID_ATTRIBUTE);
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

		List<String> aliases = new ArrayList<>();
		if (StringUtils.hasLength(nameAttr)) {
			String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			aliases.addAll(Arrays.asList(nameArr));
		}

		// id就是bean的名称,如果id没有配置,但是name配置了,就使用name的值作为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) {
			// 检查配置的beanName和别名是否唯一,之前是否有bean已经使用了这个名称
			checkNameUniqueness(beanName, aliases, ele);
		}

		// 创建beanDefinition对象
		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);
						// 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;
				}
			}
			String[] aliasesArray = StringUtils.toStringArray(aliases);
			return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
		}

		return null;
	}

  

看一下这个方法:

spring源码分析——默认标签的解析

 

 

 解析bean元素的属性、子元素的主要逻辑都在这个方法里面:

	public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, @Nullable BeanDefinition containingBean) {

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

		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 {
			// 根据className和parent来创建beanDefinition
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);

			// 解析元素的属性
			parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
			bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

			/**
			 * 以下解析的都是元素的子标签 meta、lookup-method、replaced-method、constructorArgs
			 * property、qualifier
			 */

			// 解析元数据meta
			parseMetaElements(ele, bd);

			// 解析lookup-method子元素
			parseLookupOverrideSubElements(ele, bd.getMethodOverrides());

			// 解析replaced-method子元素
			parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

			// 解析构造器注入
			parseConstructorArgElements(ele, bd);

			// 解析set属性注入
			parsePropertyElements(ele, bd);

			// 解析qualifier
			parseQualifierElements(ele, bd);

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

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

  

解析class  以及 parent属性的值

spring源码分析——默认标签的解析

 

 

 

创建beanDefinition对象:

spring源码分析——默认标签的解析

 

 

 

 spring源码分析——默认标签的解析

 

 

 

spring源码分析——默认标签的解析

 

 

  2:解析set属性依赖注入 

<property name="id" value="111"/>

<property name="dog" ref="dog"/>

入参为bean这个元素,以及刚刚创建的beanDefinition对象

spring源码分析——默认标签的解析

 

 

 

spring源码分析——默认标签的解析

 

 

 

首先解析到property上的name元素,然后根据name元素解析value的值,最后把name和value封装到PropertyValue对象上,设置到BeanDefinition上。

	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));
			// name和value的值都被封装到propertyValue对象上,然后在封装到db对象上
			bd.getPropertyValues().addPropertyValue(pv);
		}
		finally {
			this.parseState.pop();
		}
	}

  

这里的根据propertyName获取值,有value  ref  子元素等方式,具体解析的细节不在这里分析,这里只分析流程

spring源码分析——默认标签的解析

 

 

3:解析构造函数注入方式

spring源码分析——默认标签的解析

 

 

spring源码分析——默认标签的解析

遍历并且解析子元素:

 spring源码分析——默认标签的解析

 

 

	/**
	 * Parse a constructor-arg element.
	 */
	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));
						// 解析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));
						// 如果index索引重复,那么赋值时会报错
						if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {
							error("Ambiguous constructor-arg entries for index " + index, ele);
						}
						else {
							// 把index与valueHolder封装到ConstructorArgumentValues对象,再把该对象设置到bd上
							bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder);
						}
					}
					finally {
						this.parseState.pop();
					}
				}
			}
			catch (NumberFormatException ex) {
				error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele);
			}
		}
		// 如果index不存在
		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));
				// 会把valueHolder的值封装到GenericArgumengValue中
				bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
			}
			finally {
				this.parseState.pop();
			}
		}
	}

  

第一种,包含index索引的情况:

解析元素的value值,过程和解析set注入property的流程一样,然后封装到valueHolder对象中,最后把index 和 valueHolder设置到beanDefinition的contructorArgumentValues的属性上

spring源码分析——默认标签的解析

 

 

其他的元素也是一样,解析完成后,把名称、类型以及值的信息封装到对象上,然后设置到beanDefinition对象上。

bean元素解析完成,将属性设置到beanDefinition对象上,然后返回到上一步,封装到了BeanDefinitionHolder对象上维护。

spring源码分析——默认标签的解析

 

 spring源码分析——默认标签的解析

 

 

返回bdHolder对象后,如果不为null,会对它进行一个包装(自定义标签的解析,后面章节分析),然后注册。

spring源码分析——默认标签的解析

 

 

注册beanDefinition对象以及beanName

spring源码分析——默认标签的解析

 

 注册就是把beanDefinition放入beanDefinitionMap的缓存中,key为beanName,value 为beanDefinition对象,beanNames放入beanDefinitionNames缓存中

spring源码分析——默认标签的解析

 

 

注册别名:

spring源码分析——默认标签的解析

 

 

	// 注册别名
	@Override
	public void registerAlias(String name, String alias) {
		Assert.hasText(name, "'name' must not be empty");
		Assert.hasText(alias, "'alias' must not be empty");
		synchronized (this.aliasMap) {
			// 如果别名和beanName相等,则从别名缓存中删除别名,然后报错
			if (alias.equals(name)) {
				this.aliasMap.remove(alias);
				if (logger.isDebugEnabled()) {
					logger.debug("Alias definition '" + alias + "' ignored since it points to same name");
				}
			}
			else {
				String registeredName = this.aliasMap.get(alias);
				if (registeredName != null) {
					// 别名已经存在
					if (registeredName.equals(name)) {
						// An existing alias - no need to re-register
						return;
					}
					// 不允许重写报错
					if (!allowAliasOverriding()) {
						throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" +
								name + "': It is already registered for name '" + registeredName + "'.");
					}
					if (logger.isDebugEnabled()) {
						logger.debug("Overriding alias '" + alias + "' definition for registered name '" +
								registeredName + "' with new target name '" + name + "'");
					}
				}
				checkForAliasCircle(name, alias);
				// 放入别名缓存
				this.aliasMap.put(alias, name);
				if (logger.isTraceEnabled()) {
					logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");
				}
			}
		}
	}

  

spring源码分析——默认标签的解析

 

 

到这里默认标签的解析工作就完成了

总结:默认标签主要包括import bean  alias 等,以bean元素为例,

1:首先解析id  class 属性,创建beanDefinition对象

2:解析bean元素可能配置的属性,子元素等信息 例如:property元素,constructor元素,lookup 等元素,解析完成后,

将数据封装到对应的对象上,然后设置到beanDefinition对象属性中,然后返回。

3:将beanDefinition放在到holder上,判断默认元素是否包含自定义元素,包括则进行解析,将数据设置到beanDefinition对象上

4:注册,注册beanDefinition到beanDefinitionMap集合中,注册beanName到beanDefinitionNames集合中,注册别名到aliasMap中

 

上一篇:spring源码解析 - spring容器加载源码(beandefinition封装和注册过程)


下一篇:Spring XML Bean 定义的加载和注册