Spring源码阅读之IoC容器初始化3 -- BeanDefinition在IoC容器中的注册
2013-04-18 16:46
1136 查看
注1:Spring源码基于Spring3.1版本
注2:参考《Spring技术内幕》第二版
前面分析了IoC容器初始化过程中的Resource资源定位和BeanDefinition的载入与解析两个步骤,现在再分析一下在完成BeanDefinition的载入与解析后,Spring是如何将解析所得的BeanDefinition向IoC容器注册的。
在BeanDefinition载入与解析完成之后,BeanDefinition信息已经在IoC容器内部建立起了自己的数据结构,但这些数据还不能供IoC容器直接使用,需要在IoC容器中对这些BeanDefinition数据进行注册。在DefaultListableBeanFactory中,是通过一个HashMap类型的成员变量beanDefinitionMap 来持有载入的BeanDefinition的,在DefaultListableBeanFactory的源码部分可以看到:
将解析得到的BeanDefinition向IoC容器中的beanDefinitionMap注册的过程是在载入BeanDefinition完成后进行的。而前面的分析注重的是BeanDefinition的载入与解析,没有分析到BeanDefinition向IoC容器这一分支上来,看下面这段代码:
在上面这段代码中,方法的第一句代码是调用BeanDefinitionParserDelegate的parseBeanDefinitionElement方法具体解析<bean>标签,返回的是BeanDefinitionHolder对象,该对象持有BeanDefinition、Bean的名字以及别名等信息,这是前面分析的重点;而接下来的代码便是向IoC容器注册BeanDefinition了,调用的是BeanDefinitionReaderUtils工具类中的registerBeanDefinition方法,将前面解析得到的BeanDefinitionHolder以及IoC容器对象(DefaultListableBeanFactory类实现了BeanDefinitionRegistry接口)作为参数传进方法中。
下面就跟着代码去看一下注册是如何发生的。
BeanDefinitionReaderUtils类中的registerBeanDefinition方法:
上面代码显示,其实真正完成BeanDefinition注册的是BeanDefinitionRegistry的registerBeanDefinition方法,而DefaultListableBeanFactory类实现了BeanDefinitionRegistry接口,所以真正完成BeanDefinition注册正是DefaultListableBeanFactory类本身。
DefaultListableBeanFactory源码:
BeanDefinition向IoC容器的注册到这里就完成了。当完成了所有BeanDefinition的注册,IoC容器的初始化过程也就完成了。此时在IoC容器DefaultListableBeanFactory中已经建立了整个Bean的配置信息,而且这些BeanDefinition已经可以被容器使用了,它们都被维护在BeanDefinitionMap里。容器的作用就是对这些Bean信息进行维护和处理,这些信息是容器建立控制反转的基础。
注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信息进行维护和处理,这些信息是容器建立控制反转的基础。
相关文章推荐
- Spring源码阅读之IoC容器初始化2 -- BeanDefinition载入与解析
- Spring源码阅读--BeanDefinition 在 IOC 容器中的注册
- Spring源码解析-BeanDefinition在IOC容器中的注册(三)
- spring 技术内幕--IOC初始化之BeanDefinition的在IOC容器中的注册
- 【Spring源码--IOC容器的实现】(四)BeanDefinition的注册
- spring技术内幕笔记:IoC容器的初始化过程(3)- BeanDefinition的注册
- (spring-第8回【IoC基础篇】)BeanDefinition在IoC容器中的注册
- 【Spring源码--IOC容器的实现】(三)BeanDefinition的载入和解析【II】
- Ioc容器beanDefinition-Spring 源码系列(1)
- 【Spring Framework 深入】—— IoC容器初始化 -> BeanDefinition的注册
- 【Spring源码--IOC容器的实现】(三)BeanDefinition的载入和解析【I】
- spring技术内幕笔记:IoC容器初始化过程(2)- BeanDefinition的载入
- 【Spring源码--IOC容器的实现】(二)BeanDefinition的Resource定位
- Spring源码之旅(3)_BeanDefinition的解析与注册
- 深探spring系列-----ioc初始化(1)BeanDefinition的Resource定位
- 【死磕 Spring】----- IOC 之 注册 BeanDefinition
- spring IOC源码学习(二):BeanDefinition资源加载
- Spring源码阅读 --BeanDefinition
- 初始化IoC容器(Spring源码阅读)-我们到底能走多远系列(31)
- 初始化IoC容器(Spring源码阅读)