spring默认标签解析之bean标签解析与注册

1.默认标签的解析

1>.默认标签的解析是在DefaultBeanDefinitionDocumentReader类的parseDefaultElement函数中进行的,函数的功能逻辑一目了然,分别对四种不同的标签(import,alias,bean和beans)做了不同的处理;

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

2.bean标签的解析及注册

1>.进入函数processBeanDefinition(ele,delegate);

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// Register the final decorated instance.
				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));
		}
}

大致的逻辑如下:

①.首先委托BeanDefinitionParserDelegate类的parseBeanDefinitionElement方法进行元素解析,返回 BeanDefinitionHolder类型的实例bdHolder,经过这个方法之后,bdHolder实例已经包含了我们配置文件中配置的各种属性了,例如class,name,id,alias之类的属性;

②.当返回的bdHolder不为空的情况下,若存在默认标签的子节点下再有自定义属性,则还需要再次对自定义标签解析;

③.解析完成之后,需要对解析后的bdHolder进行注册,同样,注册操作委托给了BeanDefinitionReaderUtils的registerBeanDefinition方法;

④.最后发出响应事件,通知相关的监听器,这个bean已经加载完成了;
在这里插入图片描述

2.1.解析BeanDefinition

下面我们就针对各个操作做具体分析.首先我们从元素解析及信息提取开始,也就是BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele),进入BeanDefinitionParserDelegate类的parseBeanDefinitionElement方法;

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


@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
    //解析id属性
	String id = ele.getAttribute(ID_ATTRIBUTE);
    //解析name属性
	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));
	}

	String beanName = id;
	if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
		beanName = aliases.remove(0);
		if (logger.isDebugEnabled()) {
			logger.debug("No XML 'id' specified - using '" + beanName +
						"' as bean name and " + aliases + " as aliases");
		}
	}

	if (containingBean == null) {
		checkNameUniqueness(beanName, aliases, ele);
	}

	AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
	if (beanDefinition != null) {
		if (!StringUtils.hasText(beanName)) {
			try {
                //如果不存在beanName,那么根据Spring中提供的命名规则为当前bean生成对应的beanName
				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.isDebugEnabled()) {
					logger.debug("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;
}

以上便是对默认标签解析的全过程了,虽然现在只能看到对属性id和name的解析,但是很庆幸,思路我们已经了解了.在开始对属性展开全面解析前,Spring在外层又做了一个当前层的功能架构,在当前层完成的主要工作包括如下内容:

①.提前元素中的id及name属性;

②.进一步解析其他所有属性并统一封装到GenericBeanDefinition类型的实例中;

③.如果检测到bean没有指定beanName,那么使用默认规则为此Bean生成beanName;

④.将获取到的信息封装到BeanDefinitionHolder的实例中;

我们进一步地查看步骤②中对标签其他属性的解析过程:

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

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

		String className = null;
        //解析class属性
		if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
			className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
		}
		String parent = null;
        //解析parent属性
		if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
			parent = ele.getAttribute(PARENT_ATTRIBUTE);
		}

		try {
            //创建用于承载属性的AbstractBeanDefinition类型的GenericBeanDefinition
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);

            //硬编码解析默认bean的各种属性
			parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
            //提取description
			bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
            //解析元数据
			parseMetaElements(ele, bd);
            //解析lookup-method属性
			parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            //解析replace-method属性
			parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
            //解析构造函数参数
			parseConstructorArgElements(ele, bd);
            //解析property子元素
			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;
	}

终于,bean标签的所有属性,不论常用的还是不常用的我们都看到了,接下来继续一些复杂标签属性的解析.

2.1.1.创建用于属性承载的BeanDefinition

1>.BeanDefinition是一个接口,在Spring中存在三种实现:RootBeanDefinition,ChildBeanDefinition以及GenericBeanDefinition.三种实现均继承了AbstractBeanDefinition,其中BeanDefinition是配置文件bean元素标签在容器中的内部表现形式.bean元素标签拥有class,scope,lazy-init等配置属性,BeanDefinition则提供了相应的beanClass,scope,lazyInit属性,BeanDefinition和bean元素标签中的属性是一一对应的,其中RootBeanDefinition是最常用的实现类,它对应一般性的bean元素标签,GenericBeanDefinition是自2.5版本以后新加入的bean文件配置属性定义类,是一站式服务类;

2>.在配置文件中可以定义父bean元素标签和子bean元素标签,父bean元素标签用RootBeanDefinition表示,而子bean元素标签则用ChildBeanDefinition表示,而没有父bean元素标签的bean元素标签就使用RootBeanDefinition表示.AbstractBeanDefinition对两者共同的类信息进行抽象.

3>.Spring通过BeanDefinition将配置文件中的bean元素标签的配置信息转换为容器的内部表示,并将这些BeanDefinition注册到BeanDefinitionRegistery中.Spring容器的BeanDefinitionRegistery就像是Spring配置信息的内存数据库,主要是以map的形式保存,后续操作直接从BeanDefinitionRegistery中读取配置信息.它们之间的关系如下图所示:
在这里插入图片描述
由此可知,要解析属性首先要创建用于承载属性的实例,也就是创建GenericBeanDefinition类型的实例.而代码createBeanDefinition(className,parent)的作用就是实现此功能.

protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName) throws ClassNotFoundException {
    
	return BeanDefinitionReaderUtils.createBeanDefinition(parentName, className, this.readerContext.getBeanClassLoader());
}

BeanDefinitionReaderUtils类的createBeanDefinition方法

public static AbstractBeanDefinition createBeanDefinition(
			@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {

		GenericBeanDefinition bd = new GenericBeanDefinition();
        //parentName可能为空
		bd.setParentName(parentName);
		if (className != null) {
			if (classLoader != null) {
                //如果classLoader不为空,则使用以传人的classLoader同一虚拟机加载类对象,否则只是记录className
				bd.setBeanClass(ClassUtils.forName(className, classLoader));
			}
			else {
				bd.setBeanClassName(className);
			}
		}
		return bd;
}
2.1.2.解析各种属性

当我们创建了bean信息的承载实例后,便可以进行bean信息的各种属性解析了,首先我们进入BeanDefinitionParserDelegate类的parseBeanDefinitionAttributes方法.该方法是对element所有元素属性进行解析:

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

        //解析singleton属性
		if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
			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) {
			//在嵌入beanDefinition情况下且没有单独指定scope属性则使用父类默认的属性
			bd.setScope(containingBean.getScope());
		}
        //解析abstract属性
		if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
			bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
		}
        //解析lazy-init属性
		String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
		if (DEFAULT_VALUE.equals(lazyInit)) {
			lazyInit = this.defaults.getLazyInit();
		}
        //若没有设置或者设置成其他字符都会被设置为false
		bd.setLazyInit(TRUE_VALUE.equals(lazyInit));

        //解析autowire属性
		String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
		bd.setAutowireMode(getAutowireMode(autowire));

        //解析dependency-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);
			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;
}

我们可以清楚的看到Spring完成了对所有bean属性的解析,这些属性中有很多是我们经常使用的;

2.1.3.解析子元素meta

1>.在开始解析元数据的分析前,我们先回顾一下元数据meta属性的使用

<bean id="myTestBean" class="com.test.bean.MyTestBean">
    <meta key="testStr" value="abc" />
</bean>

这段代码并不会体现在MyTestBean的属性当中,而是一个额外的声明,当需要使用里面的信息时,可以通过BeanDefinition的getAttribute(key)方法进行获取.

2>.对meta属性的解析代码如下:(BeanDefinitionParserDelegate类的parseMetaElements方法)

public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) {
	//获取当前节点的所有子元素
    NodeList nl = ele.getChildNodes();
	for (int i = 0; i < nl.getLength(); i++) {
		Node node = nl.item(i);
        //提取meta
		if (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT)) {
			Element metaElement = (Element) node;
			String key = metaElement.getAttribute(KEY_ATTRIBUTE);
			String value = metaElement.getAttribute(VALUE_ATTRIBUTE);
            //使用key,value构造BeanMetadataAttribute
			BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);
			attribute.setSource(extractSource(metaElement));
            //记录信息
			attributeAccessor.addMetadataAttribute(attribute);
		}
	}
}
2.1.4.解析子元素lookup-method

1>.同样,子元素lookup-method似乎并不是很常用,但是在某些时候它的确是非常有用的属性,通常我们称它为获取器注入.引用 Spring in Action中的一句话:获取器注入是一种特殊的方法注入,它是把一个方法声明为返回某种类型的bean,但实际要返回的bean是在配置文件里面配置的,此方法可用在设计有些可插拔的功能上,解除程序依赖.

2>.我们来看看具体的应用:
①.创建一个父类

package test.lookup.bean;

public class User{
   public void showMe(){
       System.out.println("I'm user");
   }
}

②.创建其子类并覆盖showMe方法

package test.lookup.bean;

public class Teacher extends User{
    public void showMe(){
        System.out.println("I'm teacher");
    }
}

③.创建调用方法

public abstract class GetBeanTest{
    public void showMe(){
        this.getBean.showMe();
    }
    
    public abstract User getBean();
}

④.创建测试方法

public class Main{
	public static void main(String[] args){
        ApplicationContext bf = new ClassPathXmlApplicationContext("test/lookup/lookupTest.xml");
        GetBeanTest test= (GetBeanTest) bf.getBean("getBeanTest");
        test.showMe();
    }
}

⑤.配置文件

<bean id="getBeanTest" class="test.lookup.app.GetBeanTest">
    <lookup-method name="getBean" bean="teacher"/>
</bean>

<bean id="teacher" class="test.lookup.bean.Teacher"></bean>

在配置文件中,我们看到了源码中提到的lookup-method子元素,这个配置完成的功能是动态地将teacher代表的bean作为getBean的返回值,运行测试方法可以看到控制台上的输出:

I’m teacher

⑥.当我们的业务变更或者在其他情况下,teacher里面的业务逻辑已经不再符合我们的业务要求,需要进行替换怎么办?这时需要增加新的逻辑类:

package test.lookup.bean;

public class Student extends User{
    public void showMe(){
        System.out.println("I'm student");
    }
}

⑦.同时修改配置文件

<bean id="getBeanTest" class="test.lookup.app.GetBeanTest">
    <lookup-method name="getBean" bean="student"/>
</bean>

<bean id="teacher" class="test.lookup.bean.Teacher"></bean>
<bean id="student" class="test.lookup.bean.Student"></bean>

再次运行测试类,输出结果就不一样了:

I’m student

至此,我们已经初步了解了lookup-method子元素所提供的大致功能,相信这时再次去看它的属性提取源码会觉得更有针对性;

public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) {
		NodeList nl = beanEle.getChildNodes();
		for (int i = 0; i < nl.getLength(); i++) {
			Node node = nl.item(i);
            //仅当在Spring默认bean的子元素下且为<lookup-method>时有效
			if (isCandidateElement(node) && nodeNameEquals(node, LOOKUP_METHOD_ELEMENT)) {
				Element ele = (Element) node;
                //获取要修饰的方法
				String methodName = ele.getAttribute(NAME_ATTRIBUTE);
                //获取配置返回的bean
				String beanRef = ele.getAttribute(BEAN_ELEMENT);
				LookupOverride override = new LookupOverride(methodName, beanRef);
				override.setSource(extractSource(ele));
				overrides.addOverride(override);
			}
		}
}

上面的代码很眼熟,似乎与parseMetaElements的代码大同小异,最大的区别就是在if条件判断中的节点名称在这里被修改为LOOKUP_METHOD_ELEMENT.还有,在数据存储上面通过使用LookupOverride类型的实体类来进行数据承载并记录在AbstractBeanDefinition中的methodOverrides属性中.

2.1.5.解析子元素replaced-method

1>.这个方法主要是对bean中replaced-method子元素的提取,在开始提取分析之前我们还是预先介绍下这个元素的用法.

2>.方法替换: 可以在运行时动态的用新的方法替换现有的方法.与之前的lookup-method不同的是,replaced-method不但可以动态的替换返回实体bean,而且还能动态地更改原有方法的逻辑.

3>.使用示例:
①.在一个changeMethod方法中完成某个业务逻辑

public class TestChangeMethod{
    public void changeMethod(){
        System.out.println("changeMethod");
    }
}

②.在运行一段时间之后需要改变原有的业务逻辑

public class TestMethodRεplacer implements MethodReplacer{
    @Override
    public Object reimplement(Object obj,Method method,Object[] args)throws Throwable{
    	System.out.println("我替换了原来的方法");
        return null;
    } 
}

③.使替换后的类生效

<bean id="testChangeMethod" class="test.replacemethod.TestChangeMethod">
    <replaced-method name="changeMethod" replacer="replacer"/>
</bean>
<bean id="replacer" class="test.replacemethod.TestMethodReplacer"/>

④.测试

public static void main(String[] args){
    ApplicationContext bf = new ClassPathXmlApplicationContext("test/replacemethod/replaceMethodTes.xml");
    TestChangeMethod test=(TestChangeMethod) bf.getBean("testChangeMethod");
    test.changeMethod();
}

好了,运行测试类就可以看到预期的结果了,控制台成功打印出"我替换了原来的方法",也就说我们做到了动态替换原有方法,知道了这个元素的用法,我再次来看元素的提取过程:

public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides) {
		NodeList nl = beanEle.getChildNodes();
		for (int i = 0; i < nl.getLength(); i++) {
			Node node = nl.item(i);
            //仅当在Spring默认bean的子元素下且为<replaced-method>时有效
			if (isCandidateElement(node) && nodeNameEquals(node, REPLACED_METHOD_ELEMENT)) {
				Element replacedMethodEle = (Element) node;
                //提取要替换的旧的方法
				String name = replacedMethodEle.getAttribute(NAME_ATTRIBUTE);
                //提取对应的新的替换方法
				String callback = replacedMethodEle.getAttribute(REPLACER_ATTRIBUTE);
				ReplaceOverride replaceOverride = new ReplaceOverride(name, callback);
				// Look for arg-type match elements.
				List<Element> argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, ARG_TYPE_ELEMENT);
				for (Element argTypeEle : argTypeEles) {
                    //记录参数
					String match = argTypeEle.getAttribute(ARG_TYPE_MATCH_ATTRIBUTE);
					match = (StringUtils.hasText(match) ? match : DomUtils.getTextValue(argTypeEle));
					if (StringUtils.hasText(match)) {
						replaceOverride.addTypeIdentifier(match);
					}
				}
				replaceOverride.setSource(extractSource(replacedMethodEle));
				overrides.addOverride(replaceOverride);
			}
		}
}

我们可以看到无论是lookup-method还是replaced-method都是构造了一个MethodOverride,并最终记录在了AbstractBeanDefinition中的methodOverrides属性中.

2.1.6.解析子元素constructor-arg

1>.对构造函数的解析是非常常用的,同时也是非常复杂的,相信大家对构造函数的配置都不陌生,举个简单的小例子:

<!-- 默认的情况下是按照参数的顺序注入,当指定index索引后就可以改变注入参数的顺序 -->
<bean id="helloBean" class="com.HelloBean">
    <constructor-arg index="0">
        <value>张三</value>
    </constructor-arg>
    <constructor-arg index="1">
        <value>李四</value>
    </constructor-arg>
</bean>

上面的配置是Spring构造函数配置中最基础的配置,实现的功能就是对HelloBean自动寻找对应的构造函数,并在初始化的时候将设置的参数传入进去.那么让我们来看看具体的XML解析过程.

2>.对于constructor-arg子元素的解析,Spring是通过parseConstructorArgElements函数来实现的,具体代码如下:

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)) {
                //解析constructor-arg
				parseConstructorArgElement((Element) node, bd);
			}
		}
}

这个结构似乎我们可以想象得到,遍历所有的子元素,也就是提取所有的constructor-arg,然后进行解析,但是具体的解析却被放置在了另外一个函数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)) {
			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));
                        //解析ele对应的属性元素
						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 {
            //没有index属性则自动寻找
			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();
			}
		}
}

分析:

①.首先提取constructor-arg上必要的属性(index,type,name);

②.如果配置中指定了index属性,那么操作步骤如下:

I.解析constructor-arg子元素.

II.使用ConstructorArgumentValues.ValueHolder类型来封装解析出来的元素.

III.将type,name和index属性一并封装在ConstructorArgumentValues.ValueHolder类型中并添加到当前BeanDefinition的constructorArgumentValues的indexedArgumentValues属性中.

②.如果没有指定index属性,那么操作步骤如下:

I.解析constructor-arg子元素.

II.使用ConstructorArgumentValues.ValueHolder类型来封装解析出来的元素.

III.将type,name和index属性一并封装在ConstructorArgumentValues.ValueHolder类型中并添加到当前BeanDefinition的constructorArgumentValues的genericArgumentValues属性中.

可以看到,对于是否指定index属性来说,Spring的处理流程是不同的.关键在于属性信息被保存的位置.

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

		//一个属性只能对应一种类型,如:ref,value,list等
		NodeList nl = ele.getChildNodes();
		Element subElement = null;
		for (int i = 0; i < nl.getLength(); i++) {
			Node node = nl.item(i);
            //对应description或者meta,则不处理
			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;
				}
			}
		}
        //解析constructor-arg上的ref属性
		boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
        //解析constructor-arg上的value属性
		boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
		if ((hasRefAttribute && hasValueAttribute) ||
				((hasRefAttribute || hasValueAttribute) && subElement != null)) {
            /*
             * 在constructor-arg上不存在:
             *  ①.同时既有ref属性又有value属性
             *  ②.存在ref属性或者value属性且又有子元素
             */
			error(elementName +
					" is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
		}

		if (hasRefAttribute) {
            //ref属性的处理,使用RuntimeBeanReference封装对应的ref名称
			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 {
			//既没有ref也没有value也没有子元素,Spring处理不了了.
			error(elementName + " must specify a ref or value", ele);
			return null;
		}
}

从代码上来看,对构造函数中属性元素的解析,经历了以下几个过程:

①.略过description或者meta.

②.提取constructor-arg上的ref和value属性,以便于根据规则校验其正确性,其规则为在constructor-arg上不存在以下情况:

I.同时既有ref属性又有value属性.

II.存在ref属性或者value属性且又有子元素.

③.ref属性的处理.使用RuntimeBeanReference封装对应的ref名称,如:<constructor-arg ref=“a”>.

④.value属性的处理.使用TypedStringValue封装,如:<constructor-arg value=“a”>.

⑤.子元素的处理,如:

<constructor-arg>

<map>

​ <entry key=“key” value=“value”/>

</map>

</constructor-arg>

而对于子元素的处理,例如这里提到的在构造函数中又嵌入了子元素map是怎么实现的呢?parsePropertySubElement函数中实现了对各种子元素的分类处理.

@Nullable
public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd) {
		return parsePropertySubElement(ele, bd, null);
}

@Nullable
public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd, @Nullable String defaultValueType) {
		if (!isDefaultNamespace(ele)) {
			return parseNestedCustomElement(ele, bd);
		}
		else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
			BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
			if (nestedBd != null) {
				nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
			}
			return nestedBd;
		}
		else if (nodeNameEquals(ele, REF_ELEMENT)) {
			// A generic reference to any name of any bean.
			String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
			boolean toParent = false;
			if (!StringUtils.hasLength(refName)) {
				// 解析parent
				refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);
				toParent = true;
				if (!StringUtils.hasLength(refName)) {
					error("'bean' or 'parent' is required for <ref> element", ele);
					return null;
				}
			}
			if (!StringUtils.hasText(refName)) {
				error("<ref> element contains empty target attribute", ele);
				return null;
			}
			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;
		}
		else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {
            //解析array子元素
			return parseArrayElement(ele, bd);
		}
		else if (nodeNameEquals(ele, LIST_ELEMENT)) {
            //解析list子元素
			return parseListElement(ele, bd);
		}
		else if (nodeNameEquals(ele, SET_ELEMENT)) {
            //解析set子元素
			return parseSetElement(ele, bd);
		}
		else if (nodeNameEquals(ele, MAP_ELEMENT)) {
            //解析map子元素
			return parseMapElement(ele, bd);
		}
		else if (nodeNameEquals(ele, PROPS_ELEMENT)) {
            //解析props子元素
			return parsePropsElement(ele);
		}
		else {
			error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
			return null;
		}
}

可以看到,在上面的函数中实现了所有可支持的子类的分类处理.

2.1.7.解析子元素property

1>.parsePropertyElement函数完成了对property属性的提取,property使用方式如下:

<bean id="test" class="test.TestClass">
    <property name="testStr" value="aaa"></property>
</bean>

或者

<bean>
	<property name="p">
    	<list>
        	<value>aa</value>
            <value>bb</value>
        </list>
    </property>
</bean>

具体的解析过程如下:

public void parsePropertyElements(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, PROPERTY_ELEMENT)) {
				parsePropertyElement((Element) node, bd);
			}
		}
}

有了之前分析构造函数的经验,这个函数我们并不难理解,无非是提取所有property的子元素,然后调用parsePropertyElement函数进行处理.parsePropertyElement函数代码如下:

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 pv = new PropertyValue(propertyName, val);
			parseMetaElements(ele, pv);
			pv.setSource(extractSource(ele));
			bd.getPropertyValues().addPropertyValue(pv);
		}
		finally {
			this.parseState.pop();
		}
}

可以看到上面函数与构造函数注入方式不同的是将返回值使用PropertyValue进行封装,并记录在了BeanDefinition中的propertyValues属性中.

2.1.8.解析子元素qualifier

1>.对于qualifier元素的获取,我们接触更多的是注解的形式,在使用Spring框架中进行自动注入时,Spring容器中匹配的候选Bean数目必须有且仅有一个.当找不到一个匹配的Bean时,Spring容器将抛出BeanCreationException异常.并指出必须至少拥有一个匹配的Bean;

2>.Spring允许我们通过Qualifier指定注入Bean的名称,这样歧义就消除了.而对于配置方法如下:

<bean id="myTestBean" class="bean.MyTestBean">
    <qualifier type="org.Springframework.beans.factory.annotation.Qualifier" value="qf"></qualifier>
</bean>

其解析过程与之前大同小异,这里不再重复叙述.

2.2.AbstractBeanDefinition属性

1>.至此我们便完成了对XML文档到GenericBeanDefinition的转换,也就是说,到这里XML中所有的配置都可以在GenericBeanDefinition的实例类中找到对应的配置.

2>.GenericBeanDefinition只是子类实现.而大部分的通用属性都保存在了AbstractBeanDefinition中,那么我们再次通过AbstractBeanDefinition的属性来回顾一下我们都解析了哪些对应的配置.

public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
		implements BeanDefinition, Cloneable {

	//此处省略静态变量以及final常量

    //bean的作用范围,对应bean属性scope
	@Nullable
	private String scope = SCOPE_DEFAULT;

    //是否为抽象,对应bean属性abstract
	private boolean abstractFlag = false;

    //是否延迟加载,对应bean属性lazy-init
	private boolean lazyInit = false;

    //自动注入模式,对应bean属性autowire
	private int autowireMode = AUTOWIRE_NO;

    //依赖检查.Spring3.0后弃用这个属性
	private int dependencyCheck = DEPENDENCY_CHECK_NONE;

    //用来表示一个bean的实例化依靠另一个bean先实例化,对应bean属性depend-on
	@Nullable
	private String[] dependsOn;

    //autowire-candidate属性设置为false,这样容器在查找自动装配对象时,
    //将不考虑该bean,即它不会被考虑作为其他bean自动装配的候选者,但是该bean本身还是可以使用自动装配来注入其他bean     //的.对应bean属性autowire-candidate
	private boolean autowireCandidate = true;

    //自动装配时当出现多个bean换选者时,将作为首选者,对应bean属性primary
	private boolean primary = false;

    //用于记录Qualifier,对应子元素qualifier
	private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>(0);

	@Nullable
	private Supplier<?> instanceSupplier;

    //允许访问非公开的构造器和方法,程序设置
	private boolean nonPublicAccessAllowed = true;

    //是否以一种宽松的模式解析构造函数,默认为true
    //如果为false,则出现以下情况:
    //interface ITest{}
    //class ITestimpl implements ITest{}
    //class Main{
    //  Main(ITest i){}
    //  Main(ITestImpl i){}
    //}
    //抛出异常,因为Spring无法准确定位哪个构造函数
    //程序设置
	private boolean lenientConstructorResolution = true;

    //对应bean属性factory-bean
	@Nullable
	private String factoryBeanName;

    //对应bean属性factory-method
	@Nullable
	private String factoryMethodName;

    //记录构造函数注入属性,对应bean属性constructor-arg
	@Nullable
	private ConstructorArgumentValues constructorArgumentValues;

    //普通属性集合
	@Nullable
	private MutablePropertyValues propertyValues;

    //方法重写的持有者,记录lookup-method,replaced-method元素
	@Nullable
	private MethodOverrides methodOverrides;

    //初始化方法,对应bean属性init-method
	@Nullable
	private String initMethodName;

    //销毁方法,对应bean属性destroy-method
	@Nullable
	private String destroyMethodName;

    //是否执行init-method,程序设置
	private boolean enforceInitMethod = true;

    //是否执行destroy-method,程序设置
	private boolean enforceDestroyMethod = true;

    //是否是用户定义的而不是应用程序本身定义的,创建AOP时候为true,程序设宜
	private boolean synthetic = false;

    //定义这个bean的应用,APPLICATION:用户;INFRASTRUCTURE:完全内部使用,与用户无关;
    //SUPPORT:某些复杂配笠的一部分
    //程序设置
	private int role = BeanDefinition.ROLE_APPLICATION;

    //bean的描述信息
	@Nullable
	private String description;

    //这个bean定义的资源
	@Nullable
	private Resource resource;
    
    //后面的代码省略
}

2.3.解析默认标签中的自定义标签元素

到这里我们已经完成了分析默认标签的解析与提取过程,或许涉及的内容太多,我们已经忘了我们从哪个函数开始的了,我们再次回顾下默认标签解析函数的起始函数:

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// Register the final decorated instance.
				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));
		}
}

前面我们已经分析了BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele)这句代码,接下来,我们要进行bdHolder = delegate.decorateBeanDefinitionIfRequired(ele,bdHolder)代码的分析,首先大致了解下这句代码的作用,其实我们可以从语义上分析:如果需要的话就对beanDefinition进行装饰,那这句代码到底是什么功能呢?其实这句代码适用于这样的场景,如:

<bean id="test" class="test.MyClass">
   <mybean:user username="aaa"/>
</bean>

当Spring中的bean使用的是默认的标签配置,但是其中的子元素却使用了自定义的配置时,这句代码便会起作用了.之前讲过,对bean的解析分为两种类型:默认类型的解析和自定义类型的解析.这不正是自定义类型的解析吗?为什么会在默认类型解析中单独添加一个方法处理呢?请注意这个自定义类型并不是以Bean的形式出现的.前面讲过两种类型的不同处理只是针对bean的,这里我们看到,这个自定义类型其实是属性.继续分析下这段代码的逻辑:

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

这里将函数中第三个参数设置为空,其实第三个参数是父类bean,当对某个嵌套配置进行分析时,这里需要传递父类beanDefinition.这里传递的参数其实是为了使用父类的scope属性,以备子类在没有设置scope时默认使用父类的属性,这里分析的是顶层配置,所以传递null.进一步跟踪函数:

public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
			Element ele, BeanDefinitionHolder definitionHolder, @Nullable BeanDefinition containingBd) {

		BeanDefinitionHolder finalDefinition = definitionHolder;

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

通过上面的代码,我们看到函数分别对元素的所有属性以及子节点进行了decorateIfRequired函数的调用,继续跟踪代码

public BeanDefinitionHolder decorateIfRequired(
			Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {

        //获取自定义标签的命名空间
		String namespaceUri = getNamespaceURI(node);
        //对于非默认标签进行修饰
		if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
            //根据命名空间找到对应的处理器
			NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
			if (handler != null) {
                //进行修饰
				BeanDefinitionHolder decorated =
						handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
				if (decorated != null) {
					return decorated;
				}
			}
			else if (namespaceUri.startsWith("http://www.springframework.org/")) {
				error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
			}
			else {
				// A custom namespace, not to be handled by Spring - maybe "xml:...".
				if (logger.isDebugEnabled()) {
					logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
				}
			}
		}
		return originalDef;
}

程序走到这里,条理已经非常清楚了,先获取属性或者元素的命名空间,以此来判断该元素或者属性是否适用于自定义标签的解析条件,找出自定义类型所对应的NamespaceHandler并进一步解析.

总结decorateBeanDefinitionIfRequired函数的作用:

在decorateBeanDefinitionIfRequired函数中我们可以看到对于程序默认的标签的处理其实是直接略过的.因为默认的标签到这里已经被处理完了,这里只对自定义的标签或者说对bean的自定义属性进行处理.在方法中实现了寻找自定义标签并根据自定义标签寻找命名空间处理器,然后进行进一步的解析.

2.4.注册解析的BeanDefinition

对于配置文件,解析完成了,装饰也完成了,对于得到的beanDefinition已经可以满足后续的使用要求了,唯一还剩下的工作就是注册了,也就是processBeanDefinition函数中的BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());代码的解析了.

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

从上面的代码可以看出,解析的beanDefinition都会被注册到BeanDefinitionRegistery类型的实例registery中,而对于beanDefinition的注册分成了两部分:通过beanName的注册以及通过别名的注册.

2.4.1.通过beanName注册BeanDefinition

对于beanDefinition的注册,或者很多人认为的方式就是将beanDefinition直接放入map中就好了,使用beanName作为key.确实,Spring就是这么做的,只不过除此之外,它还做了点别的事情(DefaultListableBeanFactory.registerBeanDefinition)

@Override
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");

		if (beanDefinition instanceof AbstractBeanDefinition) {
			try {
                //注册前的最后一次校验,这里的校验不同于之前的XML文件校验
                //主要是对于AbstractBeanDefinition属性中的methodOverride校验
                //校验methodOverride是否与工厂方法并存或者methodOverride对应的方法根本不存在
				((AbstractBeanDefinition) beanDefinition).validate();
			}
			catch (BeanDefinitionValidationException ex) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Validation of bean definition failed", ex);
			}
		}
    
		BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
        //处理已经注册的beanName情况
		if (existingDefinition != null) {
            //如果对应的BeanName已经注册且在配置中配置了bean不允许被覆盖,那么抛出异常
			if (!isAllowBeanDefinitionOverriding()) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
						"': There is already [" + existingDefinition + "] bound.");
			}
			else if (existingDefinition.getRole() < beanDefinition.getRole()) {
				// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
				if (logger.isWarnEnabled()) {
					logger.warn("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.isInfoEnabled()) {
					logger.info("Overriding bean definition for bean '" + beanName +
							"' with a different definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			else {
				if (logger.isDebugEnabled()) {
					logger.debug("Overriding bean definition for bean '" + beanName +
							"' with an equivalent definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		else {
			if (hasBeanCreationStarted()) {
				// Cannot modify startup-time collection elements anymore (for stable iteration)
				synchronized (this.beanDefinitionMap) {
					this.beanDefinitionMap.put(beanName, beanDefinition);
					List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
					updatedDefinitions.addAll(this.beanDefinitionNames);
					updatedDefinitions.add(beanName);
					this.beanDefinitionNames = updatedDefinitions;
					if (this.manualSingletonNames.contains(beanName)) {
						Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
						updatedSingletons.remove(beanName);
						this.manualSingletonNames = updatedSingletons;
					}
				}
			}
			else {
				//注册beanDefinition
				this.beanDefinitionMap.put(beanName, beanDefinition);
                //记录beanName
				this.beanDefinitionNames.add(beanName);
				this.manualSingletonNames.remove(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}

		if (existingDefinition != null || containsSingleton(beanName)) {
            //重置所有beanName对应的缓存
			resetBeanDefinition(beanName);
		}
}

通过上面的代码我们可以看到,在对于bean的注册处理方式上,主要进行了以下几个步骤:

①.对AbstractBeanDefinition进行校验,但是这里的校验跟之前解析XML文件时做的校验是不一样的,之前是针对XML格式的校验,而这里的校验是针对AbstractBeanDefinition的methodOverrides属性的.

②.对于beanName已经注册的情况的处理.如果设置了不允许bean的覆盖,则需要抛出异常,否则直接覆盖.

③.加入到map缓存.

④.清除解析之前留下的对应beanName的缓存.

2.4.2.通过别名注册BeanDefinition

SimpleAliasRegistery类的registerAlias方法

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与alias相同的话,不记录alias,并删除对应的alias
            if (alias.equals(name)) {
                this.aliasMap.remove(alias);
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Alias definition '" + alias + "' ignored since it points to same name");
                }
            } else {
                String registeredName = (String)this.aliasMap.get(alias);
                if (registeredName != null) {
                    if (registeredName.equals(name)) {
                        return;
                    }
                    //如果alias不允许被被盖则抛出异常
                    if (!this.allowAliasOverriding()) {
                        throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" + name + "': It is already registered for name '" + registeredName + "'.");
                    }

                    if (this.logger.isInfoEnabled()) {
                        this.logger.info("Overriding alias '" + alias + "' definition for registered name '" + registeredName + "' with new target name '" + name + "'");
                    }
                }

                //循环检查,当A->B存在时,若再次出现A->C->B的时候则抛出异常
                this.checkForAliasCircle(name, alias);
                //注册alias
                this.aliasMap.put(alias, name);
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Alias definition '" + alias + "' registered for name '" + name + "'");
                }
            }

        }
}

通过上面的代码可以得知.注册alias的步骤如下:

①.alias与beanName相同情况处理.若alias与beanName名称相同,则不需要处理,还要删除原有的alias.

②.alias覆盖处理.若aliasName已经使用并已经指向了另一个beanName,则需要用户的设置进行处理.

③.alias循环检查.当A->B存在时,若再次出现A->C->B的时候,则会抛出异常.

④.注册alias.

2.5.通知监昕器解析及注册完成

通过代码getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));完成此工作,这里的实现只为扩展,当程序开发人员需要对注册BeanDefinition事件进行监听时可以通过注册监听器的方式将处理逻辑写入监听器中,目前在Spring中并没有对此事件做任何逻辑处理.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值