Spring IOC容器初始化

  在spring IOC容器的设计中,有2种主要的容器系列,一种是实现BeanFactory接口的简单容器系列,这系列容器只实现了容器的最基本功能;另一种是ApplicationContext应用上下文,它作为容器的高级形态存在。应用上下文在简单的容器基础上,增加了许多面向框架的特性,同时对应用环境做了许多适配。下面这张图描述了IOC容器的主要接口设计:

              

 

  • 从接口BeanFactory到HierarchicalBeanFactory,再到ConfigurableBeanFactory,是一条主要的BeanFactory设计路径。BeanFactory接口定义了基本的IOC容器的规范,在这个接口中包括了getBean()这样的IOC容器基本方法,而HierarchicalBeanFactory接口在继承了BeanFactory之后,增加了getParentBeanFactory的接口功能,是BeanFctory具备了双亲IOC容器的管理功能,在紧接着的ConfigurableBeanFactory中主要定义了一些对BeanFactory的配置功能,比如setBeanFactory()设置双亲IOC容器,addBeanPostProcessor()配置bean后置处理器,等等。
  • 第二条接口设计的主线是,以ApplicationContext应用上下文接口为核心的接口设计,主要涉及到的接口有:从BeanFactory到ListableBeanFactory,再到ApplicationContext,再到常用的WebApplicationContext或者ConfigurableApplicationContext。我们常用的应用上下文基本都是ConfigurableApplicationContext或者WebApplicationContext的接口实现。在这个接口体系中,ListableBeanFactory和HierarchicalBeanFactory两个接口,连接BeanFactory接口定义和ApplicationContext应用上下文的接口定义。在ListableBeanFactory接口中细化了许多BeanFactory的接口功能,比如定义了getBeanDefinitionNames()接口方法,对于ApplicatonContext接口,通过继承MessageSource,ResourcePatternResolver,ApplicationEventPublisher接口,在BeanFactory简单IOC容器的基础上添加了许多对高级容器的特性的支持。

BeanFactory容器设计原理  

  BeanFactory接口提供了使用IOC容器的规范。在这个基础上,spring还提供了符合这个IOC容器接口的一系列容器的实现供开发人员使用,XmlBeanFactory是典型的代表类,但是由于spring3版本以后XmlBeanFactory就已经被废弃了,本文是基于spring的4.3.8.RELEASE版本,所以这里就不详细描述了,直接看下接口和类的关系图了解下就好 :

              

ApplicationContext容器设计原理

  在ApplicationContext容器中,我们以常用的FileSystemXmlApplicationContext的实现为例来说明ApplicationContext容器的设计原理。

  在FileSystemXmlApplicationContext的设计中,我们看到ApplicationContext应用上下文的主要功能已经在FileSystemXmlApplicationContext的基类AbstractXmlApplicationContext中实现了,在FileSystemXmlApplicationContext中,作为一个具体的应用上下文,只需要实现和它自身设计相关的两个功能。

  一个功能是,如果应用直接使用FileSystemXmlApplicationContext,对于实例化这个应用上下文的支持,同时启动IOC容器的refresh()过程。代码如下:

    public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
        super(parent);
        this.setConfigLocations(configLocations);
        if(refresh) {
            this.refresh();
        }

    }

这个refresh()过程会牵涉IOC容器启动的一系列复杂操作,同时,对于不同的容器实现,这些操作都是类似的,因此在基类中将他们封装好。所以,我们在FileSystemXml中看到的只是一个简单的调用。

  另一个功能是与FileSystemXmlApplicationContext设计具体相关的功能,这部分与如何从文件系统中加载xml的bean定义资源有关。 通过这个过程,可以为在文件系统中读取以xml形式存在的BeanDefinition做准备,因为不同的应用上下文实现对应着不同的读取BeanDefinition的方式,在FileSystemXmlApplicationContext中的实现代码如下:

    protected Resource getResourceByPath(String path) {
        if(path != null && path.startsWith("/")) {
            path = path.substring(1);
        }

        return new FileSystemResource(path);
    }

 IOC容器初始化过程

  IOC容器的初始化是由前面介绍的refresh()方法来启动的,这个方法标志着IOC容器的正式启动,大概的流程我简易的画了下流程图,主要分为3个步骤:

                        

  第一步是Resource的定位,这个Resource指的是BeanDefinition的资源定位,它是由ResourceLoader通过统一的Resouorce接口来完成。这个Resource对各种形式的BeanDefinition的使用都提供了统一的接口。对于这些BeanDefinition的存在形式,相信大家应该都不会感到陌生。比如,在文件系统中的Bean定义信息可以使用FileSystemResource来进行抽象;在类路径的Bean定义信息可以使用ClassPathResource来使用,等等。这个定位过程类似容器寻找数据的过程,就像用水桶装水先要把水找到一样。

  第二步是BeanDefinition的载入,这个过程是把用户定义好的bean表示成IOC容器内部的数据结构,而这个容器内部的数据结构就是BeanDefinition,具体来说,这个BeanDdefinition实际上就是POJO对象在IOC容器中的抽象,通过这个BeanDefinition定义的数据结构,是IOC容器能够方便的对POJO对象也就是Bean进行管理。

  第三步是向IOC容器注册这些BeanDefinition,这个过程是通过调用BeanDefinitionRegistry接口的实现来完成的。这个注册过程把载入过程中解析得到的BeanDefinition向IOC容器进行注册,我们看一个简单的实现类(SimpleBeanDefinitionRegistry)具体代码:

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

    public SimpleBeanDefinitionRegistry() {
    }

    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
        Assert.hasText(beanName, "\'beanName\' must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");
        this.beanDefinitionMap.put(beanName, beanDefinition);
    }

  通过代码,我们可以看到,在IOC容器内部将BeanDefinition注入到一个HashMap中,IOC就是通过这个HashMap来持有这些BeanDefinition对象的。

 有一点需要注意,这里谈的是IOC容器的初始化过程,在这个过程中一般不包含Bean依赖注入的实现。在Spring IOC的设计中,Bean定义的载入和依赖载入是2个独立的过程。依赖注入一般发生在应用第一次通过getBean向容器索取Bean的时候。但有一个例外值得注意,在使用IOC容器时有一个预实例化的配置,通过这个预实例化的配置(具体来说,可以通过为Bean定义信息中的 lazyinit属性),用户可以对容器初始化过程做一个微小的控制,从而改变这个被设置了lazyinit属性的Bean的依赖注入过程。举个例,如果我们对某个Bean设置了lazyinit属性,那么这个Bean的依赖注入在IOC容器初始化的时候就已经完成了,而不需要等到整个初始化完成以后,第一次使用getBean时才触发。

 1.BeanDefinition的Resource定位

  以编程的方式使用DefaultListableBeanFactory时,首先定义一个Resource来定位容器使用的BeanDefinition。这时使用的是ClassPathResource,这意味着spring会在类路径中去寻找以文件形式存在的BeanDefinition信息。

ClassPathResource res = new ClassPathResource("beans.xml");

这里定义的Resource并不能由DefaultListableBeanFactory直接使用,spring通过BeanDefinitionReader来对这些信息进行处理。在这里我们也可以看到使用ApplicationContext相对于直接使用DefaultListableBeanFactory的好处。因为在ApplicationContext中,spring已经为我们提供了一些列加载不同Resource的读取器的实现。而DefaultListableBeanFactory只是一个纯粹的IOC容器,需要为它配置特定的读取器才能完成这些功能。当然有机就有弊,使用DefaultListableBeanFactory这种更底层的容器,能提高定制IOC容器的灵活性。回到我们常用的ApplicationContext上来,例如FileSystemXMLApplicationContext、ClassPathXMLApplicationContext以及XMLWebApplicationContext等。简单的从这些类名字上分析,可以清楚的看到他们提供哪些不同的Resource读入功能。下面以分析FileSystemXMLApplicationContext为例,来看看它如何完成这个Resource的定位过程,先看下它相应的ApplicationContext继承体系:

                      

 从上图中可以看到,FileSystemXmlApplicationContext通过继承AbstractApplicationContext具备了ResourceLoader读入以Resource定义的BeanDefinition的能力,因为AbstractApplicationContext的基类是DefaultResourceLoader。我们看看FileSystemXMLApplicationContext的核心代码:

//在对象的初始化过程中,调用refresh函数载入BeanDefinition,这个refresh方法启动了BeanDefinition的载入过程
public
FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); this.setConfigLocations(configLocations); if(refresh) { this.refresh(); } }   //这是应用于文件系统中Resource的实现,通过构造一个FileSystemResource来得到一个在文件系统中定位的BeanDefinition
  //这个getResourceByPath是在BeanDefinitionReader的loadBeanDefinition中被调用的,loadBeanDefinition采用了模板模式,具体的定位实现实际上是由各个子类完成
protected Resource getResourceByPath(String path) { if(path != null && path.startsWith("/")) { path = path.substring(1); } return new FileSystemResource(path); }

 我们再来看看方法调用的关系图:

  

  在FileSystemXmlApplicationContext的构造方法中调用了refresh()方法,该方法是IOC容器初始化的重要入口,它会进行一系列的初始化操作,这里我们只讨论Resource的定位问题。在它的父类AbstractApplicationContext的refresh()实现方法中,会调用refreshBeanFactory()方法,在该方法中会根据容器已有的双亲IOC容器的信息来生成DefaultListableBeanFactory的双亲IOC容器,然后会对bean进行解析,看一段AbstractRefreshableApplicationContext的核心代码:

protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            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);
        }
    }

注意 上面加下划线的代码,createBeanFactory()就是生成DefaultListableBeanFactory双亲IOC容器的地方,而loadBeanDefinitions方法是用来载入Bean的地方,在该方法里面,通过XmlBeanDefinitionReader来载入,因为可以有多种载入方式(虽然xml方式用得比较多),它通过一个抽象函数把具体的实现委托给子类来完成。继续深入loadBeanDefinition的具体实现方法:

 public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
        ResourceLoader resourceLoader = this.getResourceLoader();
        if(resourceLoader == null) {
            throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
        } else {
            int loadCount;
            if(!(resourceLoader instanceof ResourcePatternResolver)) {
                Resource var11 = resourceLoader.getResource(location);
                loadCount = this.loadBeanDefinitions((Resource)var11);
                if(actualResources != null) {
                    actualResources.add(var11);
                }

                if(this.logger.isDebugEnabled()) {
                    this.logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
                }

                return loadCount;
            } else {
                try {
                    Resource[] resource = ((ResourcePatternResolver)resourceLoader).getResources(location);
                    loadCount = this.loadBeanDefinitions(resource);
                    if(actualResources != null) {
                        Resource[] var6 = resource;
                        int var7 = resource.length;

                        for(int var8 = 0; var8 < var7; ++var8) {
                            Resource resource1 = var6[var8];
                            actualResources.add(resource1);
                        }
                    }

                    if(this.logger.isDebugEnabled()) {
                        this.logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
                    }

                    return loadCount;
                } catch (IOException var10) {
                    throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", var10);
                }
            }
        }
    }

代码里面获取的ResourceLoader使用的是DefaultResourceLoader,然后对Resource的路径模式进行解析,在下划线的地方,调用DefaultResourceLoader的getResource方法完成具体的Resource定位,而在getResource的实现代码中,调用的就是DefaultResourceLoader的getResourceByPath(),这个方法在FileSystemXmlApplicationContext中被实现,这个方法返回的是一个FileSystemResource对象,通过这个对象,spring可以进行相关的I/O操作,完成BeanDefinition的定位。

 2.BeanDefinition的载入和解析

   在完成对代表BeanDefinition的Resource定位的分析后,下面来了解整个BeanDefinition的载入过程。对于IOC容器来说,这个载入过程相当于把定义的BeanDefinition在IOC容器中转化成一个Spring内部表示的数据结构的过程。IOC容器的管理和依赖注入功能的实现,是通过对其持有的BeanDefinition进行各种相关操作来完成的。这些BeanDefinition数据在IOC容器中通过一个HashMap来保持和维护。下面,从DefaultListableBeanFactory入手,看看IOC容器如何完成BeanDefinition载入的,DeFaultListableBeanFactory在上面已经提到过很多次,应该不会感到陌生。先看一张BeanDefinition载入的方法调用图:

  

首先入口还是在AabstractApplicationContext了的refresh()方法,上源码:

@Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            
            prepareRefresh();

            // 这里是在之类中启动refreshBeanFactory的地方
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            
            prepareBeanFactory(beanFactory);

            try {
                // 设置BeanFactory的后置处理器
                postProcessBeanFactory(beanFactory);

                // 调用BeanFactory的后处理器,这些后处理器是在bean定义中向容器注册的
                invokeBeanFactoryPostProcessors(beanFactory);

                // 注册bean的后处理器,在bean创建过程中调用
                registerBeanPostProcessors(beanFactory);

                // 对上下文中的消息源进行初始化
                initMessageSource();

                // 初始化上下文中的事件机制
                initApplicationEventMulticaster();

                // 初始化其他特殊的bean
                onRefresh();

                // 检查监听bean并将这些bean向容器注册
                registerListeners();

                // 实例化所有的non-lazy-init单件
                finishBeanFactoryInitialization(beanFactory);

                // 发布容器事件,结束refresh过程
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // 为防止bean资源占用,在异常处理中,销毁已经在前面生成的单件bean
                destroyBeans();

                // 重置active标志
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }

 这里还是只关心BeanDefinition的载入,看启动refreshBeanFactory的地方: obtainFreshBeanFactory(),在这个方法里面调用了refreshBeanFactory(),在这个方法里创建了BeanFactory,在创建IOC容器之前,如果已经有容器存在,那么需要把已有的容器销毁和关闭,保证在refresh以后使用的都是新建立的IOC容器,上面分析Resource定位时已经看过refreshBeanFactory的源码,载入也是在这个方法里面。调用的是loadBeanDefinitions方法,这个方法实际上是一个抽象方法,那么实际的载入过程到底发生在哪呢?我们看看前面提到的loadBeanDefinitions在AbstractRefreshableApplicationContext的子类AbstractXmlApplicationContext中的实现,在这个loadBeanDefinitions中,初始化了读取器XmlBeanDefinitionReader,然后把这个读取器在IOC容器中设置好,最后启动读取器来完成在IOC容器中的载入,看下源码:

@Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        // Create a new XmlBeanDefinitionReader for the given BeanFactory.
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        // Configure the bean definition reader with this context's
        // resource loading environment.
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

        // Allow a subclass to provide custom initialization of the reader,
        // then proceed with actually loading the bean definitions.
        initBeanDefinitionReader(beanDefinitionReader);
        loadBeanDefinitions(beanDefinitionReader);
    }
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}

Spring可以对应不同形式的BeanDefinition,由于这里使用的是xml方式的定义,所以需要使用XMLBeanDefinitionReader。如果使用了其他方式的BeanDefinition方式,就需要使用其他方式的BeanDefinitionReader来完成载入。在读取器中,需要得到代表XML文件的Resource (具体如果得到请看上面Resource的定位),因为这个Resource对象封装了对XML的I/O操作,所以读取器可以在打开IO流后得到XML的文件对象,有了这个对象以后,就可以按照spring的bean定义规则来对这个xml文档树进行解析了。这个解析是交给BeanDefinitionParserDelegate来完成的,具体如何解析对象这里不详细分析,如果感兴趣的可以去DefaultDocumentLoader这个类去看源码。我们这里关心的是Spring的BeanDefinition是怎样按照Spring的bean语义要求进行解析并转化为容器内部数据结构的。这个过程是在XmlBeanDefinition中的registerBeanDefinitions(Document doc, Resource resource)方法中完成的,这个方法还对载入的bean的数量进行了统计,看下源码:

    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();
        int countBefore = this.getRegistry().getBeanDefinitionCount();
     //具体的解析过程在这个registerBeanDefinintions里面完成 documentReader.registerBeanDefinitions(doc,
this.createReaderContext(resource)); return this.getRegistry().getBeanDefinitionCount() - countBefore; }

BeanDefinition的载入分为2部分,首先通过调用XML的解析器得到Document对象,但这些document对象并没有按照spring的bean规则进行解析,完成通用的XML解析以后,才是按照spring的bean规则进行解析的,这个解析过程是在documentReader中实现的,这里使用的documentReader是默认设置好的DefaultBeanDefinitionDocumentReader,这个reader的创建是在后面的方法中完成的,然后在完成BeanDefinition的处理,处理的结果由BeanDefinitionHolder对象来持有。这个BeanDefinitionHolder除了持有BeanDefintion对象外,还持有其他与BeanDefinition的使用相关的信息,比如Bean的名字、别名集合等。这个BeanDefinitionHolder的生成是通过对Document文档树的内容进行解析来完成的,这个过程是在DefaultBeanDefinitionDocumentReader里面的processBeanDefinition方法中实现的。最后看下源码:

public interface BeanDefinitionDocumentReader {
    void registerBeanDefinitions(Document var1, XmlReaderContext var2) throws BeanDefinitionStoreException;
}
//=======实现类里面的方法==========================================================================
    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        this.readerContext = readerContext;
        this.logger.debug("Loading bean definitions");
        Element root = doc.getDocumentElement();
        this.doRegisterBeanDefinitions(root);
    }
//===================================================================================================
protected void doRegisterBeanDefinitions(Element root) {
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = this.createDelegate(this.getReaderContext(), root, parent);
        if(this.delegate.isDefaultNamespace(root)) {
            String profileSpec = root.getAttribute("profile");
            if(StringUtils.hasText(profileSpec)) {
                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, ",; ");
                if(!this.getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                    if(this.logger.isInfoEnabled()) {
                        this.logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + this.getReaderContext().getResource());
                    }

                    return;
                }
            }
        }

        this.preProcessXml(root);
        this.parseBeanDefinitions(root, this.delegate);
        this.postProcessXml(root);
        this.delegate = parent;
    }
//==================================================================================================
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)) {
                        this.parseDefaultElement(ele, delegate);
                    } else {
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        } else {
            delegate.parseCustomElement(root);
        }

    }
//==============================================================================================
    private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        if(delegate.nodeNameEquals(ele, "import")) {
            this.importBeanDefinitionResource(ele);
        } else if(delegate.nodeNameEquals(ele, "alias")) {
            this.processAliasRegistration(ele);
        } else if(delegate.nodeNameEquals(ele, "bean")) {
            this.processBeanDefinition(ele, delegate);
        } else if(delegate.nodeNameEquals(ele, "beans")) {
            this.doRegisterBeanDefinitions(ele);
        }

    }
//==================================================================================================
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if(bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

            try {
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
            } catch (BeanDefinitionStoreException var5) {
                this.getReaderContext().error("Failed to register bean definition with name \'" + bdHolder.getBeanName() + "\'", ele, var5);
            }

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

    }

 3.BeanDefinition在IOC容器中的注册

  前面已经分析过BeanDefinition在IOC容器中载入和解析的过程,在这些动作完成以后,用户定义的BeanDefinition信息已经在IOC容器内建立起了自己的数据结构以及相应的数据表示,但此时这些数据还不能供IOC容器直接使用,需要在IOC容器中对这些BeanDefinition进行注册。这个注册为IOC容器提供了更友好的使用方式,在BeanDefaultListableBeanFactory中,是通过一个HashMap来持有载入的BeanDefinition的,这个HashMap的定义在上面的代码中已经展示过。来看下注册的调用过程:

      

注册过程是紧跟在解析过程后面的,在DefaultBeanDefinitionDocumentReader类中的processBeanDefinition方法中调用了registerBeanDefinition方法(代码可以参考第二部分解析的源码),在解析BeanDefinition后就向IOC容器注册,主要是在DefaultListableBeanFactory中实现的BeanDefinitionRegister接口,这个过程并不复杂,就是把解析得到的BeanDefinition设置到HashMap中去。需要注意的是,如果遇到同名的BeanDefinition,进行处理时需要依据 allowBeanDefinitionOverriding的配置来完成,看下源码:

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 {
                ((AbstractBeanDefinition)beanDefinition).validate();
            } catch (BeanDefinitionValidationException var9) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var9);
            }
        }

        BeanDefinition oldBeanDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
        if(oldBeanDefinition != null) {
            if(!this.isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean \'" + beanName + "\': There is already [" + oldBeanDefinition + "] bound.");
            }

            if(oldBeanDefinition.getRole() < beanDefinition.getRole()) {
                if(this.logger.isWarnEnabled()) {
                    this.logger.warn("Overriding user-defined bean definition for bean \'" + beanName + "\' with a framework-generated bean definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
                }
            } else if(!beanDefinition.equals(oldBeanDefinition)) {
                if(this.logger.isInfoEnabled()) {
                    this.logger.info("Overriding bean definition for bean \'" + beanName + "\' with a different definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
                }
            } else if(this.logger.isDebugEnabled()) {
                this.logger.debug("Overriding bean definition for bean \'" + beanName + "\' with an equivalent definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
            }

            this.beanDefinitionMap.put(beanName, beanDefinition);
        } else {
            if(this.hasBeanCreationStarted()) {
                Map var4 = this.beanDefinitionMap;
                synchronized(this.beanDefinitionMap) {
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    ArrayList updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    if(this.manualSingletonNames.contains(beanName)) {
                        LinkedHashSet updatedSingletons = new LinkedHashSet(this.manualSingletonNames);
                        updatedSingletons.remove(beanName);
                        this.manualSingletonNames = updatedSingletons;
                    }
                }
            } else {
                this.beanDefinitionMap.put(beanName, beanDefinition);
                this.beanDefinitionNames.add(beanName);
                this.manualSingletonNames.remove(beanName);
            }

            this.frozenBeanDefinitionNames = null;
        }

        if(oldBeanDefinition != null || this.containsSingleton(beanName)) {
            this.resetBeanDefinition(beanName);
        }

    }

完成了BeanDefinition的注册,就完成了整个IOC容器的初始化过程。此时,在使用的IOC容器DefaultListableBeanFactory中已经建立了整个Bean的配置信息,而且这些BeanDefinition已经可以被容器使用了,他们都在BeanDefinitionMap里被检索和使用。容器的作用就是对这些信息进行处理和维护。

posted @ 2017-06-29 14:45  莫莫莫  阅读(274)  评论(0)    收藏  举报