Spring IOC源码:obtainFreshBeanFactory 详解(中)

文章目录

  • Spring源码系列:
  • 前言
  • 正文
    • 方法1:processBeanDefinition
    • 方法2:parseBeanDefinitionElement
    • 方法3:parseBeanDefinitionElement
    • 方法4:parseBeanDefinitionAttributes
    • 方法5:parseConstructorArgElements
    • 方法6:parseConstructorArgElement
    • 方法7:parsePropertyValue
    • 方法8:parsePropertySubElement
    • 方法9:parsePropertyElements
    • 方法10:registerBeanDefinition
    • 方法11:registerBeanDefinition
    • 方法12:resetBeanDefinition
    • 方法13:resetBeanDefinition
  • 总结

Spring源码系列:

Spring IOC源码:简单易懂的Spring IOC 思路介绍
Spring IOC源码:核心流程介绍
Spring IOC源码:ApplicationContext刷新前准备工作
Spring IOC源码:obtainFreshBeanFactory 详解(上)
Spring IOC源码:obtainFreshBeanFactory 详解(中)
Spring IOC源码:obtainFreshBeanFactory 详解(下)
Spring IOC源码:<context:component-scan>源码详解
Spring IOC源码:invokeBeanFactoryPostProcessors 后置处理器详解
Spring IOC源码:registerBeanPostProcessors 详解
Spring IOC源码:实例化前的准备工作
Spring IOC源码:finishBeanFactoryInitialization详解
Spring IoC源码:getBean 详解
Spring IoC源码:createBean( 上)
Spring IoC源码:createBean( 中)
Spring IoC源码:createBean( 下)
Spring IoC源码:finishRefresh 完成刷新详解

前言

上篇文章我们介绍了prepareRefresh方法,配置解析前的准备工作,和obtainFreshBeanFactory方法,配置解析核心处理方法。我们讲解到了parseBeanDefinitions方法,该方法会根据命名空间去选择对应的逻辑处理。本章节介绍默认命名空间的处理逻辑parseDefaultElement(ele, delegate);

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		//判断当前命名空间是否为默认
		if (delegate.isDefaultNamespace(root)) {
			NodeList nl = root.getChildNodes();
			for (int i = 0; i < nl.getLength(); i++) {
				Node node = nl.item(i);
				if (node instanceof Element) {
					Element ele = (Element) node;
					if (delegate.isDefaultNamespace(ele)) {
						//默认命名空间节点的处理,例如: 
						parseDefaultElement(ele, delegate);
					}
					else {
						// 自定义命名空间节点的处理,例如:
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			//非默认命名空间走其它逻辑
			delegate.parseCustomElement(root);
		}
	}

正文

进入parseDefaultElement(ele, delegate)方法,我们可以看到有四种类型的判断,import、alias、bean、beans。这里获取一级节点,判断节点类型选择对应的解析方法。几种类型的解析都是比较类似的,这里我们使用的bean,学会的bean去看其它都是大同小异,而beans节点其实是重新调用一遍doRegisterBeanDefinitions方法,进行子节点的遍历解析工作。bean节点解析见方法1

	private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
		//解析import
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			importBeanDefinitionResource(ele);
		}
		//解析alias
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			processAliasRegistration(ele);
		}
		//解析bean
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
			processBeanDefinition(ele, delegate);
		}
		//解析beans
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			// recurse
			doRegisterBeanDefinitions(ele);
		}
	}

xml配置如下:


<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean name="teacher" class="service.impl.Teacher">
		<property name="name" value="张三">property>
		<property name="age" value="30">property>
	bean>

beans>

方法1:processBeanDefinition

	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		//通过解析器进行解析,解析出类名、class、id、父类、属性依赖等
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			//bean解析器只能解析一些默认的配置,这里判断是否有自定义的属性或子节点需要进一步解析并封装,
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// 将bdHolder 注册到上下文缓存中beanDefinitionNames、beanDefinitionMap、aliasMap
				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));
		}
	}

1、delegate.parseBeanDefinitionElement(ele)方法:见方法2详解

2、delegate.decorateBeanDefinitionIfRequired(ele, bdHolder)方法:
这个方法主要是考虑到bean节点中的属性或者子节点包含了自定义内容,默认的解析器没办法解析到,所以需要做下后置处理,判断是否有自定义的,通过自定义获取命名空间,通过命名空间加载解析器进行处理,将处理好的值封装到步骤1解析出来的BeanDefinitionHolder 中。例如下面的“zhudachang”属性和 < myBean > 子节点。这节我们要研究默认命名空间,所以这里不做深入,等后面讲解了自定义的内容后,再来看这块就比较简单了。


<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean name="teacher" class="service.impl.Teacher" zhudachang="">
		<property name="name" value="张三">property>
		<property name="age" value="30">property>
		<myBean>myBean>
	bean>

beans>

方法2:parseBeanDefinitionElement

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


	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
		//获取id和name属性值
		String id = ele.getAttribute(ID_ATTRIBUTE);
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
		//对name属性值匹配“,;”切割看是否有多个名称,加入别名缓存
		List<String> aliases = new ArrayList<>();
		if (StringUtils.hasLength(nameAttr)) {
			String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			aliases.addAll(Arrays.asList(nameArr));
		}
		//如果beanName为空,则以aliases中的第一条数据作为beanName名称,并移除。
		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");
			}
		}
		//查询一下该beanName 名称是否作为第一个被使用了
		if (containingBean == null) {
			checkNameUniqueness(beanName, aliases, ele);
		}
		//解析节点并封装成GenericBeanDefinition
		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
		if (beanDefinition != null) {
			if (!StringUtils.hasText(beanName)) {
				try {
					if (containingBean != null) {
						//默认规则生成,获取class名称,如果class名称为空,则看beanDefinition的父类或FactoryBean的名称+固定后最作为Bean名称,如果是内部的Bean则按另一个逻辑生成;
						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);
			//将beanDefinition跟类名、别名封装成 BeanDefinitionHolder
			return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
		}

		return null;
	}

1、beanName的获取规则,如果bean节点配置了id属性,则以id作为beanName。如果没有id,但是有配置name属性,则解析名称中是否含有多个,如果有多个则将第一个作为beanName,其余的作为别名,加入aliases集合中。
例如:

	<bean name="ZHU,DA,CHANG" class="service.impl.Teacher">
		<property name="name" value="张三">property>
		<property name="age" value="30">property>
	bean>

这里的beanName为"ZHU",别名为“DA”,“CHANG"

	<bean id="teacher" name="zhudachang" class="service.impl.Teacher">
		<property name="name" value="张三">property>
		<property name="age" value="30">property>
	bean>

这里的beanName为"teacher",别名为“zhudachang”

2、parseBeanDefinitionElement(ele, beanName, containingBean)方法:见方法3详解

方法3:parseBeanDefinitionElement

	public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, @Nullable BeanDefinition containingBean) {
		//将beanName封装成BeanEntry对象
		this.parseState.push(new BeanEntry(beanName));
		//获取class类属性
		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 {
			//创建GenericBeanDefinition,并设置父类名称,通过className获取class并设置
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);
			//解析设置各种属性
			parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
			//设置description信息
			bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
			//解析元数据
			parseMetaElements(ele, bd);
			//设置LookupOverride
			parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
			//设置ReplacedMethod
			parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
			//解析设置构造函数节点
			parseConstructorArgElements(ele, bd);
			//解析设置子节点属性
			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;
	}

1、parseBeanDefinitionAttributes(ele, beanName, containingBean, bd)方法,见方法4详解
2、parseLookupOverrideSubElements(ele, bd.getMethodOverrides())
该方法主要解析子节点中的< lookup-method >标签,该标签处理Bean中属性为原型模式,也就是每次获取该属性时都会新创建一个对象。
如:Teacher类中声明了Address属性,而我们的Address是prototype原型模式,也就是每次获取该值都会创建一个新的对象,而Teacher是一个单例,获取该类时,每次都从缓存中获取,导致类中的Adress也是一个单例,这里就是为后续处理该问题作准备。后续文章会专门讲解这个的用法。

	<bean name="address" class="service.Address" scope="prototype">bean>
	<bean id="teacher" name="teacher" class="service.impl.Teacher" >
		<lookup-method name="getAddress" bean="address">lookup-method>
	bean>

3、parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

	<bean name="address" class="service.Address" scope="prototype">bean>
	<bean id="teacher" name="teacher" class="service.impl.Teacher" >
		<replaced-method name="getAddress" replacer="addressMethodReplacer">replaced-method>
	bean>

4、parseConstructorArgElements(ele, bd)方法,见方法5详解

5、parsePropertyElements(ele, bd)方法见方法9详解

方法4:parseBeanDefinitionAttributes

    // 解析设置singleton属性
    if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
        // singleton属性以被scope属性代替
        error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
    }
    // 解析设置scope属性
    else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
        bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
    }
    else if (containingBean != null) {
        // Take default from containing bean in case of an inner bean definition.
        bd.setScope(containingBean.getScope());
    }
 
    // 解析设置abstract属性
    if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
        bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
    }
 
    // 解析设置lazy-init属性, 默认为false
    String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
    if (DEFAULT_VALUE.equals(lazyInit)) {
        lazyInit = this.defaults.getLazyInit();
    }
    bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
 
    // 解析设置autowire属性
    String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
    bd.setAutowireMode(getAutowireMode(autowire));
 
    // 解析设置dependency-check属性
    String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE);
    bd.setDependencyCheck(getDependencyCheck(dependencyCheck));
 
    // 解析设置depends-on属性
    if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
        String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
        bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
    }
 
    // 解析设置autowire-candidate属性
    String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
    if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate)) {
        String candidatePattern = this.defaults.getAutowireCandidates();
        if (candidatePattern != null) {
            String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
            bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
        }
    }
    else {
        bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
    }
 
    // 解析设置primary属性
    if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
        bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
    }
 
    // 解析设置init-method属性
    if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
        String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
        if (!"".equals(initMethodName)) {
            bd.setInitMethodName(initMethodName);
        }
    }
    else {
        if (this.defaults.getInitMethod() != null) {
            bd.setInitMethodName(this.defaults.getInitMethod());
            bd.setEnforceInitMethod(false);
        }
    }
 
    // 解析设置destroy-method属性
    if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
        String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
        bd.setDestroyMethodName(destroyMethodName);
    }
    else {
        if (this.defaults.getDestroyMethod() != null) {
            bd.setDestroyMethodName(this.defaults.getDestroyMethod());
            bd.setEnforceDestroyMethod(false);
        }
    }
 
    // 解析设置factory-method属性
    if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
        bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
    }
    // 解析factory-bean属性
    if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
        bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
    }
 
    return bd;
}

方法5:parseConstructorArgElements

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

这里遍历子节点中的< constructor-arg >标签,对其属性进行解析封装,parseConstructorArgElement((Element) node, bd)方法见方法6详解

	<bean id="address"  class="service.Address" >bean>

	<bean  id="teacher" name="teacher" class="service.impl.Teacher">
		<constructor-arg index="0" value="zhangsan">constructor-arg>
		<constructor-arg index="1" value="13">constructor-arg>
		<constructor-arg index="2" ref="address">constructor-arg>
		<constructor-arg index="3" >
			<list>
				<value>zhudachang1value>
				<value>zhudachang2value>
				<value>zhudachang3value>
			list>
		constructor-arg>
	bean>

方法6:parseConstructorArgElement

public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
		//获取index属性
		String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);
		//获取type属性
		String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);
		//获取name属性
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
		if (StringUtils.hasLength(indexAttr)) {
			//如果有index属性
			try {
				int index = Integer.parseInt(indexAttr);
				if (index < 0) {
					error("'index' cannot be lower than 0", ele);
				}
				else {
					try {
						//校验该index是否>=0,否则抛异常
						this.parseState.push(new ConstructorArgumentEntry(index));
						//获取其值,可能是通过 value 属性、ref 属性、list 属性等
						Object value = parsePropertyValue(ele, bd, null);
						//封装成ConstructorArgumentValues对象
						ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
						if (StringUtils.hasLength(typeAttr)) {
						//设置type值
							valueHolder.setType(typeAttr);
						}
						if (StringUtils.hasLength(nameAttr)) {
						//设置name值
							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 {
				//如果没有index,此时不做校验
				this.parseState.push(new ConstructorArgumentEntry());
				//获取当前设置值,可能是通过 value 属性、ref 属性、list 属性等
				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();
			}
		}
	}

parsePropertyValue(ele, bd, null)方法,会解析出当前节点对应的引用类型值,见方法7详解

方法7:parsePropertyValue

public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) {
		String elementName = (propertyName != null ?
				" element for property '" + propertyName + "'" :
				" element");
		//获取该节点下的子节点
		NodeList nl = ele.getChildNodes();
		Element subElement = null;
		//如果是List类型,则有子节点。这里会对子节点进行校验
		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;
				}
			}
		}
		//判断是否有该属性
		boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
		boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
		//这里不允许有value跟ref共存或者跟有子节点的共存 如list
		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) {
			//获取属性值并将该属性值封装成RuntimeBeanReference 对象
			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) {
			//如果有value值,则封装成TypedStringValue 
			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;
		}
	}

parsePropertySubElement(subElement, bd)方法对子节点进行解析,见方法8详解

方法8:parsePropertySubElement

public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd, @Nullable String defaultValueType) {
		//判断节点标签是否是默认命名空间,不是则走自定义逻辑
		if (!isDefaultNamespace(ele)) {
			return parseNestedCustomElement(ele, bd);
		}
		else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
			//如果是Bean标签,则进行解析,并封装成BeanDefinitionHolder 
			BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
			if (nestedBd != null) {
				//判断该节点是否有自定义标签,有则调用自定义逻辑处理,补充新的解析内容进来
				nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
			}
			return nestedBd;
		}
		else if (nodeNameEquals(ele, REF_ELEMENT)) {
			// 如果是ref,引用其它Bean,获取引用的beanName名称
			String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
			boolean toParent = false;
			if (!StringUtils.hasLength(refName)) {
				// 获取父类beanName
				refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);
				toParent = true;
				if (!StringUtils.hasLength(refName)) {
					error("'bean' or 'parent' is required for  element", ele);
					return null;
				}
			}
			if (!StringUtils.hasText(refName)) {
				error(" element contains empty target attribute", ele);
				return null;
			}
			//封装成RuntimeBeanReference 
			RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
			ref.setSource(extractSource(ele));
			return ref;
		}
		//解析idref节点
		else if (nodeNameEquals(ele, IDREF_ELEMENT)) {
			return parseIdRefElement(ele);
		}
		//解析value
		else if (nodeNameEquals(ele, VALUE_ELEMENT)) {
			return parseValueElement(ele, defaultValueType);
		}
		//解析null
		else if (nodeNameEquals(ele, NULL_ELEMENT)) {
			// It's a distinguished null value. Let's wrap it in a TypedStringValue
			// object in order to preserve the source location.
			TypedStringValue nullHolder = new TypedStringValue(null);
			nullHolder.setSource(extractSource(ele));
			return nullHolder;
		}
		//解析Array数组
		else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {
			return parseArrayElement(ele, bd);
		}
		//解析List集合
		else if (nodeNameEquals(ele, LIST_ELEMENT)) {
			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);
		}
		//解析props
		else if (nodeNameEquals(ele, PROPS_ELEMENT)) {
			return parsePropsElement(ele);
		}
		else {
			error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
			return null;
		}
	}

1、list节点的解析,获取该节点下的子节点,遍历调用parsePropertySubElement,并将每个子节点添加至Collection中。
2、其它集合Map、Set、Array等的解析过程也跟list类似。

方法9:parsePropertyElements

以上我们介绍了< constructor-arg >标签的解析过程,下面来看下

	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);
			}
		}
	}
public void parsePropertyElement(Element ele, BeanDefinition bd) {
		//获取name属性值
		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 
			PropertyValue pv = new PropertyValue(propertyName, val);
			parseMetaElements(ele, pv);
			pv.setSource(extractSource(ele));
			bd.getPropertyValues().addPropertyValue(pv);
		}
		finally {
			this.parseState.pop();
		}
	}

xml配置案例如下:

	<bean id="address"  class="service.Address" scope="prototype">bean>
	<bean id="teacher" class="service.impl.Teacher">
		<property name="name" value="zhudachang">property>
		<property name="age" value="11">property>
		<property name="address" ref="address">property>
	bean>

到这里我们的解析工作就完成了,下面回到方法1中,解析后需要将BeanDefinition注册到上下文缓存中,见方法10详解

方法10:registerBeanDefinition

	public static void registerBeanDefinition(
			BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
			throws BeanDefinitionStoreException {

		// 获取beanName名称
		String beanName = definitionHolder.getBeanName();
		//注册到缓存中
		registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

		//获取别名集合,注册到上下文的别名缓存中
		String[] aliases = definitionHolder.getAliases();
		if (aliases != null) {
			for (String alias : aliases) {
				registry.registerAlias(beanName, alias);
			}
		}
	}

1、我们看到传进来的是BeanDefinitionRegistry 注册器,我们可以把它当成管理上下文的工具类吧,使用它可以操作上下文的部分增删改查工作
2、registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition())方法,见方法11详解
3、registry.registerAlias(beanName, alias)方法,见方法13详解

方法11: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");
		//如果是AbstractBeanDefinition,则校验
		if (beanDefinition instanceof AbstractBeanDefinition) {
			try {
				((AbstractBeanDefinition) beanDefinition).validate();
			}
			catch (BeanDefinitionValidationException ex) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Validation of bean definition failed", ex);
			}
		}
		//判断缓存中是否存在了该beanName的BeanDefinition 
		BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
		if (existingDefinition != null) {
			if (!isAllowBeanDefinitionOverriding()) {
				throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
			}
			else if (existingDefinition.getRole() < beanDefinition.getRole()) {
				// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
				if (logger.isInfoEnabled()) {
					logger.info("Overriding user-defined bean definition for bean '" + beanName +
							"' with a framework-generated bean definition: replacing [" +
							existingDefinition + "] with [" + beanDefinition + "]");
				}
			}
			else if (!beanDefinition.equals(existingDefinition)) {
				if (logger.isDebugEnabled()) {
					logger.debug("Overriding bean definition for bean '" + beanName +
							"' with a different definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			else {
				if (logger.isTraceEnabled()) {
					logger.trace("Overriding bean definition for bean '" + beanName +
							"' with an equivalent definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			//加入缓存中,进行覆盖
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		else {
			//检查下当前bean工厂是否开始创建工作,这里是为了加锁
			if (hasBeanCreationStarted()) {
				// Cannot modify startup-time collection elements anymore (for stable iteration)
				synchronized (this.beanDefinitionMap) {
					//将当前beanDefinition放入缓存中
					this.beanDefinitionMap.put(beanName, beanDefinition);
					//统计下数量
					List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
					updatedDefinitions.addAll(this.beanDefinitionNames);
					updatedDefinitions.add(beanName);
					this.beanDefinitionNames = updatedDefinitions;
					removeManualSingletonName(beanName);
				}
			}
			else {
				// 将当前beanDefinition放入缓存中
				this.beanDefinitionMap.put(beanName, beanDefinition);
				//将beanName加入缓存中
				this.beanDefinitionNames.add(beanName);
				removeManualSingletonName(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}
		//如果Bean存在于缓存中,并且的单例的,这里需要重置
		if (existingDefinition != null || containsSingleton(beanName)) {
			resetBeanDefinition(beanName);
		}
	}

1、((AbstractBeanDefinition) beanDefinition).validate();
该方法用于校验节点中不能同时存在factory-method属性和子节点< lookup-method >、< replaced-method >。这个if语句是为了确保,上述两者不能共存,否则就会报错。这是因为,如果给一个 Bean 配置了工厂方法,那么它会由工厂方法来创建,而不是 Spring 默认的方式创建,这种情况下无法进行方法的覆盖。因此,这里的判断是为了确保配置信息没有出现冲突。

	public void validate() throws BeanDefinitionValidationException {
		if (hasMethodOverrides() && getFactoryMethodName() != null) {
			throw new BeanDefinitionValidationException(
					"Cannot combine factory method with container-generated method overrides: " +
					"the factory method must create the concrete bean instance.");
		}
		if (hasBeanClass()) {
			prepareMethodOverrides();
		}
	}

2、resetBeanDefinition(beanName)方法,见方法12详解

方法12:resetBeanDefinition

protected void resetBeanDefinition(String beanName) {
		// 从合并的MergedBeanDefinition缓存中移除
		clearMergedBeanDefinition(beanName);
		//这里移除了很多处缓存,如IOC三级缓存等
		destroySingleton(beanName);

		// 通知后置处理器进行重置处理
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			if (processor instanceof MergedBeanDefinitionPostProcessor) {
				((MergedBeanDefinitionPostProcessor) processor).resetBeanDefinition(beanName);
			}
		}

		
		for (String bdName : this.beanDefinitionNames) {
			if (!beanName.equals(bdName)) {
				BeanDefinition bd = this.beanDefinitionMap.get(bdName);
				//当前遍历的BeanDefinition的parentName为beanName,则递归调用resetBeanDefinition进行重置
				if (bd != null && beanName.equals(bd.getParentName())) {
					resetBeanDefinition(bdName);
				}
			}
		}
	}

方法13:resetBeanDefinition

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) {
			//如果别名缓存中已经存在该数据,则移除
			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 + "'");
					}
				}
				//检查name和alias是否存在循环引用。例如A的别名为B,B的别名为A
				checkForAliasCircle(name, alias);
				//加入缓存
				this.aliasMap.put(alias, name);
				if (logger.isTraceEnabled()) {
					logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");
				}
			}
		}
	}

总结

至此,Spring 加载默认命名空间的 BeanDefinition 的过程就全部分析完了,可以说这是 BeanFactory 实例化前最复杂的逻辑了。我们梳理一下流程:
1、Spring判断是否默认命名空间,加载默认解析器进行解析
2、使用默认命名空间解析完成后得到初步的BeanDefinition对象,再调用自定义命名空间进行处理判断是否需要补充处理。
3、将解析的BeanDefinition 加入beanDefinitionMap缓存中,将beanName加入beanDefinitionNames缓存中,将aliases加入到aliasMap缓存中。
后面我们会继续讲解自定义命名空间的处理过程。

你可能感兴趣的:(spring,Java,spring,java)