您的位置:首页 > 编程语言 > Java开发

【Spring源码--IOC容器的实现】(四)BeanDefinition的注册

2016-08-18 20:14 831 查看


前言

本篇是IOC容器启动的最后一遍,也就是注册。但并不是DI(依赖注入)已经完成,这里只是完成对xml文件的解析、IOC容器的启动,具体的依赖注入需要getBean的时候完成。但是也有一个例外:那就是通过控制lazy-init属性来让容器实现对bean的预实例化。这个后面我们在讲。
当代码读到这里,可以再针对前面的代码有目的的去回顾一下,先走通主线,再根据注释尽量去理解一些周边方法。


BeanDefinition在IOC容器注册

首先我们要回忆两点:1、发起注册的地方;2、注册的实现类。
我们先来看第一点,上一篇博客前半部分我们讲了Bean的解析,在DefaultBeanDefinitionDocumentReader类的processBeanDefinition方法中,其中一个是去完成BeanDefinition的载入,另一个是完成注册。我们先来看下简略代码:

代码1.1:DefaultBeanDefinitionDocumentReader类的processBeanDefinition方法

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {

//解析方法

BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);

if (bdHolder != null) {

bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

try {

//注册方法

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

}

catch (BeanDefinitionStoreException ex) {

getReaderContext().error("Failed to register bean definition with name '" +

bdHolder.getBeanName() + "'", ele, ex);

}

getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));

}

}


现在我们找到了BeanDefinition的注册入口,我们知道BeanDefinitionHolder=BeanDefinition+beanName,所以这里数据我们是有的,来看下registerBeanDefinition的代码:

代码1.2:BeanDefinitionReaderUtils类的registerBeanDefinition方法

public static void registerBeanDefinition(

BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)

throws BeanDefinitionStoreException {


// 根据beanName注册Beandefinition.

String beanName = definitionHolder.getBeanName();

registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());


// 如果有别名,注册别名

String[] aliases = definitionHolder.getAliases();

if (aliases != null) {

for (String aliase : aliases) {

registry.registerAlias(beanName, aliase);

}

}

}


这里我们需要回忆第二点了,因为当我们找这个registerBeanDefinition的实现类的时候,会发现有三个实现类,那么具体取哪个?还记得我们最初容器建立的时候用的是什么容器么?简单回顾下代码:

代码1.3:AbstractRefreshableApplicationContext类的refreshBeanFactory方法

@Override

protected final void refreshBeanFactory() throws BeansException {

if (hasBeanFactory()) {

destroyBeans();

closeBeanFactory();

}

try {

//创建Factory

DefaultListableBeanFactory beanFactory = createBeanFactory();

beanFactory.setSerializationId(getId());

customizeBeanFactory(beanFactory);

loadBeanDefinitions(beanFactory);

synchronized (this.beanFactoryMonitor) {

this.beanFactory = beanFactory;

}

}

catch (IOException ex) {

throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);

}

}


而且,我们看下这个DefaultListFactory实现了BeanDefinitionRegistry接口,这个接口就是定义注册的。并且这个类中有这么一个HashMap,这里就是我们存放BeanDefinition的地方。
/** Map of bean definition objects, keyed by bean name */

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();


那么我们继续来看代码:

代码1.4:DefaultListableBeanFactory类的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");

//校验解析的BeanDefiniton

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) {

Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);

//检查是否有同名的BeanDefinition已经在IoC容器中注册,如果已经注册,

//并且不允许覆盖已注册的Bean,则抛出注册失败异常

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 {//如果允许覆盖,则同名的Bean,后注册的覆盖先注册的

if (this.logger.isInfoEnabled()) {

this.logger.info("Overriding bean definition for bean '" + beanName +

"': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");

}

}

}

else {

//IoC容器中没有已经注册同名的Bean,按正常注册流程注册

this.beanDefinitionNames.add(beanName);

this.frozenBeanDefinitionNames = null;

}

this.beanDefinitionMap.put(beanName, beanDefinition);

//重置所有已经注册过的BeanDefinition的缓存

resetBeanDefinition(beanName);

}

}


完了,这就结束了。到这里,代码就完成了IOC容器的初始化过程。此时,在使用的IOC容器DefaultListableBeanFactory中已经建立了整个Bean的配置信息,而且这些BeanDefinition已经可以被容器使用了,他们都在beanDefinitionMap中北检索和使用。容器的作用就是对这些信息进行处理和维护。这些信息室容器建立依赖反转的基础,有了这些基础数据,就可以完成最后的依赖注入了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: