Spring源码阅读之IoC容器初始化3 -- BeanDefinition在IoC容器中的注册

11 篇文章 0 订阅

注1:Spring源码基于Spring3.1版本

注2:参考《Spring技术内幕》第二版


前面分析了IoC容器初始化过程中的Resource资源定位和BeanDefinition的载入与解析两个步骤,现在再分析一下在完成BeanDefinition的载入与解析后,Spring是如何将解析所得的BeanDefinition向IoC容器注册的。

在BeanDefinition载入与解析完成之后,BeanDefinition信息已经在IoC容器内部建立起了自己的数据结构,但这些数据还不能供IoC容器直接使用,需要在IoC容器中对这些BeanDefinition数据进行注册。在DefaultListableBeanFactory中,是通过一个HashMap类型的成员变量beanDefinitionMap 来持有载入的BeanDefinition的,在DefaultListableBeanFactory的源码部分可以看到:

/** List of bean definition names, in registration order */
private final List
  
  
   
    beanDefinitionNames = new ArrayList
   
   
    
    ();

/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();
   
   
  
  

将解析得到的BeanDefinition向IoC容器中的beanDefinitionMap注册的过程是在载入BeanDefinition完成后进行的。而前面的分析注重的是BeanDefinition的载入与解析,没有分析到BeanDefinition向IoC容器这一分支上来,看下面这段代码:

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
	// 具体的解析委托给BeanDefinitionParserDelegate来完成
	// BeanDefinitionHolder是BeanDefinition的封装类, 封装了BeanDefinition、Bean的名字和别名, 用它来完成向IoC容器注册.
	BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
	if (bdHolder != null) {
		bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
		try {
			// 向IoC容器注册解析得到的BeanDefinition.
			BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
		} catch (BeanDefinitionStoreException ex) {
			getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex);
		}
		// BeanDefinition注册完成后, 发送事件.
		getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
	}
}

在上面这段代码中,方法的第一句代码是调用BeanDefinitionParserDelegate的parseBeanDefinitionElement方法具体解析<bean>标签,返回的是BeanDefinitionHolder对象,该对象持有BeanDefinition、Bean的名字以及别名等信息,这是前面分析的重点;而接下来的代码便是向IoC容器注册BeanDefinition了,调用的是BeanDefinitionReaderUtils工具类中的registerBeanDefinition方法,将前面解析得到的BeanDefinitionHolder以及IoC容器对象(DefaultListableBeanFactory类实现了BeanDefinitionRegistry接口)作为参数传进方法中。

下面就跟着代码去看一下注册是如何发生的。

BeanDefinitionReaderUtils类中的registerBeanDefinition方法:

public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, 
			BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
	String beanName = definitionHolder.getBeanName();
	// 向IoC容器注册BeanDefinition 
	registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

	// 如果解析的BeanDefinition有别名, 向容器为其注册别名.
	String[] aliases = definitionHolder.getAliases();
	if (aliases != null) {
		for (String aliase : aliases) {
			registry.registerAlias(beanName, aliase);
		}
	}
}

上面代码显示,其实真正完成BeanDefinition注册的是BeanDefinitionRegistry的registerBeanDefinition方法,而DefaultListableBeanFactory类实现了BeanDefinitionRegistry接口,所以真正完成BeanDefinition注册正是DefaultListableBeanFactory类本身。

DefaultListableBeanFactory源码:

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {
	// 对解析得到的BeanDefinition校验
	if (beanDefinition instanceof AbstractBeanDefinition) {
		try {
			((AbstractBeanDefinition) beanDefinition).validate();
		} catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
					"Validation of bean definition failed", ex);
		}
	}
	// 注册的过程中需要线程同步, 以保证数据的一致性
	synchronized (this.beanDefinitionMap) {
		// 检查是否有同名的BeanDefinition已经在IoC容器中注册, 如果已经注册, 并且不允许覆盖已注册的Bean, 则抛出异常
		Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);
		if (oldBeanDefinition != null) {
			if (!this.allowBeanDefinitionOverriding) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
						"': There is already [" + oldBeanDefinition + "] bound.");
			} else {
				if (this.logger.isInfoEnabled()) {
					this.logger.info("Overriding bean definition for bean '" + beanName +
							"': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
				}
			}
		} else {
			// 没有同名BeanDefinition注册过, 将Bean名字存入beanDefinitionNames
			this.beanDefinitionNames.add(beanName);
			this.frozenBeanDefinitionNames = null;
		}
		// 以BeanName为key, BeanDefinition为value存入beanDefinitionMap, 有同名BeanDefinition会覆盖.
		this.beanDefinitionMap.put(beanName, beanDefinition);

		resetBeanDefinition(beanName);
	}
}

BeanDefinition向IoC容器的注册到这里就完成了。当完成了所有BeanDefinition的注册,IoC容器的初始化过程也就完成了。此时在IoC容器DefaultListableBeanFactory中已经建立了整个Bean的配置信息,而且这些BeanDefinition已经可以被容器使用了,它们都被维护在BeanDefinitionMap里。容器的作用就是对这些Bean信息进行维护和处理,这些信息是容器建立控制反转的基础。


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值