前言
在多次对Spring的源码断点调试以及了解ApplicationContext的结构之后,发现无论是ClassPathXmlApplicationContext还是FileSystemXmlApplicationContext的初始化最终会指向AbstractApplicationContext的**refresh()**方法。
AbstractApplicationContext是一个抽象类,这个类继承了DefaultResourceLoader类,实现了ConfigurableApplicationContext和DisposableBean这2个接口。为什么要使用抽象类呢?
我个人对于这种继承某个类,然后实现多个接口的做法的理解是通过使用抽象类提供默认的实现或者是公共的逻辑。
PS:本人学习的Spring源码版本为4.3.20.RELEASE,如果看到与文章内容不一致,可能是不同版本的实现方案不同
refresh()方法解读
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//为Context的刷新准备
prepareRefresh();
//让子类刷新内部的BeanFactory,其实就是让子类调用refreshBeanFactory()方法的地方
//refreshBeanFactory()是个抽象方法,需要子类实现
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//准备用于Context的BeanFactory
prepareBeanFactory(beanFactory);
try {
//允许在AbstractApplicationContext的子类中对BeanFactory进行后置处理。
//postProcessBeanFactory()方法是个空实现
postProcessBeanFactory(beanFactory);
//调用BeanFactory的后置处理器处理BeanFactory实例
invokeBeanFactoryPostProcessors(beanFactory);
//将Bean的后置处理器注册到上下文(Context)的BeanFactory实例
//Bean的后置处理器是用于拦截Bean的创建,并对创建后的Bean实例进行处理
registerBeanPostProcessors(beanFactory);
//初始化上下文的消息资源
initMessageSource();
//初始化应用上下文的事件接收器
//表明Spring内部是基于事件机制
initApplicationEventMulticaster();
//这个方法是空实现,允许在AbstractApplicationContext的子类重写
onRefresh();
//检查监听器Bean并将这些Bean实例注册到上下文
registerListeners();
//初始化所有非懒加载的单例对象
finishBeanFactoryInitialization(beanFactory);
//发布容器刷新完成事件,完成刷新过程
finishRefresh();
}
catch (BeansException ex) { //捕获BeansException
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
//销毁所有已经创建的单例对象,避免Bean资源占用
destroyBeans();
//取消刷新,重置active标识(置为false)
cancelRefresh(ex);
//将异常传给调用者
throw ex;
}
finally {
//重置Spring中内置的自检缓存,其实就是清空缓存
resetCommonCaches();
}
}
}
心得体会
-
Spring中的BeanFactory算不算是Spring的Bean呢?
BeanFactory算Spring的Bean,不过BeanFactory是先初始化之后再注册到Spring的上下文,虽然BeanFactory本身也是Spring上下文的一部分。详情可以参考AbstractApplicationContext的refresh方法中调用的prepareBeanFactory、postProcessBeanFactory、invokeBeanFactoryPostProcessors、registerBeanPostProcessors这几个方法。 -
Spring的上下文初始化的时候只会初始化非懒加载的单例对象(参考finishBeanFactoryInitialization()方法),这是因为懒加载的单例对象本身就应该在使用到的时候才进行初始化,而多例对象则是会在调用BeanFactory.getBean()方法时创建一个新的实例。