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里被检索和使用。容器的作用就是对这些信息进行处理和维护。

浙公网安备 33010602011771号