应用上下文初始化简要流程一文中主要简要的描述了Spring的上下文加载的简要流程。文本是对《应用上下文初始化简要流程》的补充,主要简单的分析了BeanFactory的初始化以及BeanDefinition加载的过程.
我们知道,Spring通过refresh操作重建了ApplicaitonContext
,在这个过程中同时也构建了默认的BeanFactory
以及加载了BeanDefinition
。AbstractApplicationContext
类在refresh()
方法中调用了obtainFreshBeanFactory
, 此方法主要负责重建BeanFactory
以及加载BeanDefinition
。 下面我们对此方法进行简要分析。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
可以看出,此方法的主要逻辑由refreshBeanFactory()
方法实现,而refreshBeanFactory()
方法的默认实现由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);
}
}
整个refreshBeanFactory()
的逻辑是比较清晰的,首先判断是否已存在BeanFactory
,如果已存在则销毁:
destroyBeans()
清除Bean引用的缓存closeBeanFactory()
释放已创建的BeanFactory
其次调用createBeanFactory
建立默认的BeanFactoryDefaultListableBeanFactory
————一个基于Bean Definition对象的成熟的Bean工厂;
当BeanFactory建立好之后,进行一项简单的配置customizeBeanFactory()
, 以决定在加载BeanDefinition的过程中是否允许循环引用以及是否允许对已有BeanDefinition进行覆写.
最后,方法loadBeanDefinitions()
才是重头戏————BeanDefinition
的加载过程。
实现loadBeanDefinitions()
的子类有多种,如AbstractXmlApplicationContext
类提供了基于XML的加载实现,AnnotationConfigWebApplicationContext
类提供了在webapp的场景下基于注解配置的加载实现,XmlWebApplicationContext
类提供了在webapp场景下基于xml配置的加载实现,XmlPortletApplicationContext
提供了在portalet
下基于xml配置的加载实现,GroovyWebApplicationContext
类提供了基于groovy
脚本配置的加载实现。当然也可以自己实现此方法.
此处,我们主要分析基于xml的加载过程。代码如下:
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // 第一行
beanDefinitionReader.setEnvironment(this.getEnvironment()); //第二行
beanDefinitionReader.setResourceLoader(this); //第三行
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // 第四行
initBeanDefinitionReader(beanDefinitionReader); // 第五行
loadBeanDefinitions(beanDefinitionReader); // 第六行
}
第一行代码中实例化了一个XmlBeanDefinitionReader
对象,此对象用于读取xml的bean定义,实际上它会将对于xml的处理委托给BeanDefinitionDocumentReader
接口。这个对象的构造器需要传入BeanDefinitionRegistry
对象,因此此处beanFactory
作为一个BeanDefinitionRegistry
对象被使用;
在XmlBeanDefinitionReader
的构造器中调用了它的父抽象类AbstractBeanDefinitionReader
的构造器,在这个构造器中,分别为XmlBeanDefinitionReader
对象的属性resourceLoader
和Environment
赋值; 如果beanFactory
没有实现ResourceLoader
接口则会创建PathMatchingResourcePatternResolver
实例作为resourceLoader
; 如果beanFactory
没有实现EnvironmentCapable
则会创建StandardEnvironment
作为environment
; 此处beanFctory
的类型为DefaultListableBeanFactory
,因此不具备以上条件,故均采用创建对象;
PathMatchingResourcePatternResolver
类代理了DefaultResourceLoader
,对于通过简单的location获取Resource
由DefaultResourceLoader
实现,其余复杂location加载Resource
由其自己实现;此处采用的设计模式为静态代理
第二行代码为beanDefinitionReader
的environment
赋值,值为StandardEnvironment
实例(非web应用的环境)
第三行代码为beanDefinitionReader
的resourceLoader
赋值,值为当前上下文(当前对象的父类继承了DefaultResourceLoader
)
第四行代码为beanDefinitionReader
的entityResolver
赋值,值为ResourceEntityResolver
的实例.此类作为EntityResolver
的实现主要是通过ResourceLoader
来尝试解析实体引用; 此类又集成了DelegatingEntityResolver
所以也可以查找DTD和XSD。
第五行代码initBeanDefinitionReader(beanDefinitionReader)
主要是对beanDefinitionReader
进行初始化配置,默认是空实现,主要是用于子类覆盖此方法实现自定义XmlBeanDefinitionReader
的初始化配置,例如打开或者关闭XML验证,配置不同的XmlBeanDefinitionParser
实现
第六行代码loadBeanDefinitions(beanDefinitionReader)
就是BeanDefinition
的主要加载过程了.它使用指定的XmlBeanDefinitionReader
进行加载BeanDefinition
. 这个方法仅负责加载或者注册BeanDefinition
,而生命周期是通过bean工厂的refreshBeanFactory
方法管理. loadBeanDefinitions
代码如下: