基于 Spring Framework v5.2.6.RELEASE
在之前的 ApplicationContext 初始化 Spring 容器 一文中,我们提到了 AbstractApplicationContext#refresh
方法是一个非常重要的方法,它包含了 Spring 容器初始化的整个流程,我们将对这里的源码进行细致地阅读。本篇要阅读的是 BeanFactory 初始化的部分,也就是 refresh 方法中的这一行方法调用:
// Tell the subclass to refresh the internal bean factory.// 这里会调用模版方法,通过子类的实现,初始化 BeanFactory 并解析 XML 配置ConfigurableListableBeanFactorybeanFactory=obtainFreshBeanFactory();
这里调用了 obtainFreshBeanFactory
并得到了一个 ConfigurableListableBeanFactory
类型的 beanFactory
。这个方法的作用是初始化 beanFactory
,还会解析 XML 中配置的 Bean。
我们先看源码:
/*** Tell the subclass to refresh the internal bean factory.* @return the fresh BeanFactory instance* @see #refreshBeanFactory()* @see #getBeanFactory()*/protectedConfigurableListableBeanFactoryobtainFreshBeanFactory() { refreshBeanFactory(); returngetBeanFactory(); }
这个方法的源码很简单,调用了两个方法,并将第二个方法的结果返回。根据方法的名称可以看到,第一个方法用来刷新(或者初始化)beanFactory
,第二个方法用来获取 beanFactory
并返回。
refreshBeanFactory
方法
我们先看 refreshBeanFactory
方法,具体实现过程可以在 AbstractRefreshableApplicationContext
类找到 :
/*** This implementation performs an actual refresh of this context's underlying* bean factory, shutting down the previous bean factory (if any) and* initializing a fresh bean factory for the next phase of the context's lifecycle.*/protectedfinalvoidrefreshBeanFactory() throwsBeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactorybeanFactory=createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory=beanFactory; } } catch (IOExceptionex) { thrownewApplicationContextException("I/O error parsing bean definition source for "+getDisplayName(), ex); } }
从方法的整体流程可以看出,不管当前是不是存在一个 BeanFactory ,这里都会创建一个新的,并进行初始化,我们来逐行分析代码。
销毁已有的 BeanFactory
一开始,会判断当前是否存在一个 BeanFactory,如果有的话,就销毁其中的 Bean,并关闭 BeanFactory。这部分逻辑对应方法体开头的 if
语句块。因为我们分析的是 Spring 容器第一次创建时候的流程,而且之前并没有 BeanFactory 创建的逻辑,所以,目前为止,并不存在一个 BeanFactory,if
语句中的逻辑不会被执行。
实例化新的 BeanFactory
接下来就是 try
语句块中的部分。
首先,执行了 createBeanFactory
方法,创建了一个 BeanFactory。这里的代码也很简单:
protectedDefaultListableBeanFactorycreateBeanFactory() { returnnewDefaultListableBeanFactory(getInternalParentBeanFactory()); }
获取到 parent
后,调用构造方法,创建了一个 DefaultListableBeanFactory
的实例并返回。
这里的构造方法中还有一些步骤,与本文的主线内容关系不大,暂时先挖个坑,坑填之后会将链接贴在这里
DefaultListableBeanFactory
这个类型是第一次见到,我们可以大致看一下它的继承关系:
这里的接口实现关系错综复杂,可以先看看留个印象。值得一提的是,它的子类 XmlBeanFactory
是 Spring 中非常重要的一个类,是 Spring 的初级容器。如果使用 XML 配置文件来直接创建 BeanFactory 使用的就是 XmlBeanFactory
,不过现在这个类已经被标记了 @Deprecated
。
言归正传,回到 refreshBeanFactory
方法中来。创建好 BeanFactory 后,通过 beanFactory.setSerializationId(getId())
给了它一个 Id,序列化和反序列化的时候用。
对 BeanFactory 进行自定义
接下来,customizeBeanFactory(beanFactory)
执行了 ApplicationContext 对内部的 BeanFactory 的自定义。
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) { if (this.allowBeanDefinitionOverriding != null) { beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } if (this.allowCircularReferences != null) { beanFactory.setAllowCircularReferences(this.allowCircularReferences); } }
这里通过给 beanFactory
的成员变量赋值,做了两件事:
- 允许相同名称的 BeanDefinition 在容器中被覆盖
- 允许多个 Bean 之间存在循环依赖
这两点涉及到了 BeanDefinition 和 Bean 初始化的流程,根据容器初始化的整体流程(可以参考:Spring 源码阅读:ApplicationContext 初始化 Spring 容器 ),在之后的代码中应该会遇到。
加载 BeanDefinition
最后一个方法调用,loadBeanDefinitions(beanFactory);
执行了 BeanDefinition 的加载。这里的实现逻辑可以在 AbstractXmlApplicationContext
中找到:
/*** Loads the bean definitions via an XmlBeanDefinitionReader.* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader* @see #initBeanDefinitionReader* @see #loadBeanDefinitions*/protectedvoidloadBeanDefinitions(DefaultListableBeanFactorybeanFactory) throwsBeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory.XmlBeanDefinitionReaderbeanDefinitionReader=newXmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's// resource loading environment.beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(newResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader,// then proceed with actually loading the bean definitions.initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); }
在这个方法中,首先创建了一个 XmlBeanDefinitionReader
的实例,并对其进行了配置。从它的名字可以知道,这个类用来读取 XML 中的 Bean 定义。
创建好之后,末尾调用了两个方法,我们先看 initBeanDefinitionReader
的源码:
protectedvoidinitBeanDefinitionReader(XmlBeanDefinitionReaderreader) { reader.setValidating(this.validating); }
方法名告诉我们方法的作用是对 XmlBeanDefinitionReader
进行初始化,这里只是设置了是否对 XML 文件进行验证(默认值是 true
),其余什么也没干。我们还注意到,这个方法是 protected
修饰的,因此可以断定,这里是 Spring 留给我们的一个扩展点。我们可以通过重写这个方法,关闭 XML 验证、自定义 XML 的解析器,或者执行其他的一些设置。
最后将 beanDefinitionReader
作为参数,调用了另外一个 loadBeanDefinitions
方法。源码如下:
protectedvoidloadBeanDefinitions(XmlBeanDefinitionReaderreader) throwsBeansException, IOException { Resource[] configResources=getConfigResources(); if (configResources!=null) { reader.loadBeanDefinitions(configResources); } String[] configLocations=getConfigLocations(); if (configLocations!=null) { reader.loadBeanDefinitions(configLocations); } }
在这里,分别将 configResources
和 configLocations
作为参数,执行了 reader
的 loadBeanDefinitions
方法。不过,getConfigResources
这个方法直接返回了 null
,因此,这里的逻辑就是,根据我们创建 ClassPathXmlApplicationContext 时提供的配置文件路径,进行 BeanDefinition 的加载。
这里
reader.loadBeanDefinitions
方法加载 BeanDefinition 的逻辑是现在 AbstractBeanDefinitionReader#loadBeanDefinitions(java.lang.String...) 方法中,这里面还有很多流程,我打算放到另外一篇文章中,这里又挖了一个坑,填坑后我会将链接更新到这里。Spring 源码阅读 06:加载 BeanDefinition 的过程(准备阶段)
Spring 源码阅读 07:加载 BeanDefinition 的过程(资源加载阶段)
完成初始化并赋值
方法的末尾,通过 this.beanFactory = beanFactory;
将之前创建并初始化好的 BeanFactory 赋值给 beanFactory
成员变量。
getBeanFactory
方法
最后我们在回到最开始的 obtainFreshBeanFactory
方法,看一下里面调用的第二个方法 getBeanFactory()
的源码,实现逻辑在 AbstractRefreshableApplicationContext
类中:
publicfinalConfigurableListableBeanFactorygetBeanFactory() { synchronized (this.beanFactoryMonitor) { if (this.beanFactory==null) { thrownewIllegalStateException("BeanFactory not initialized or already closed - "+"call 'refresh' before accessing beans via the ApplicationContext"); } returnthis.beanFactory; } }
这里其实就是把 refreshBeanFactory
方法创建并初始化的 BeanFactory 获取到并返回。