Spring 源码学习 09:refresh 大概流程

发布于: 2020 年 12 月 23 日



前言



前面的准备工作结束之后,就是进入核心代码 refresh。



源码



public void refresh() throws BeansException, IllegalStateException {
// 加锁
synchronized (this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
// 准备一些上下文
prepareRefresh();
// 获取准备后的 beanFactory DefaultListableBeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 准备 BeanFactory
prepareBeanFactory(beanFactory);
try {
// 允许在上下文子类中对bean工厂进行后处理。
postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
// 在上下文中调用注册为 beanFactory 后置处理器
// 就是实现了 BeanFactoryPostProcessor 的 bean
invokeBeanFactoryPostProcessors(beanFactory);
// 注册后置处理的Bean到容器当中
// 就是扩展了 BeanPostProcessor 的 Bean
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
// 为此上下文初始化消息源。
// 初始化国际化工具 MessageSource
initMessageSource();
// 为此上下文初始化事件广播器。
initApplicationEventMulticaster();
// 在特定上下文子类中初始化其他特殊bean。子类可以自己实现
onRefresh();
// 检查并注册监听器。
registerListeners();
// 实例化所有剩余的(非延迟初始化)单例。
finishBeanFactoryInitialization(beanFactory);
// 最后一步: 完成此上下文的刷新,调用 LifecycleProcessor 的 onRefresh()方法并发布
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁已创建的单例以避免资源悬挂。
destroyBeans();
// 重置活动状态
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();
contextRefresh.end();
}
}
}



源码就是密密麻麻的一大堆,源码上有相应的注释。





下面就根据流程,一步一步的深入源码,了解到每一步都是做什么了。



容器刷新准备



prepareRefresh 这一步主要是准备一些上下文信息。就不过多介绍了。



obtainFreshBeanFactory





下面关注初始化 BeanFactory 这一步:



进入源码:





通过 Debug 可以看出 refreshBeanFactory() 这一步调用的是 org.springframework.context.support.GenericApplicationContext#refreshBeanFactory 中实现的方法。



继续跟进





发现这块判断了一个 refreshed 刷新状态。



refreshBeanFactory 方法也有另一个实现是在 AbstractRefreshableApplicationContext 中, 只不过我的断点没有断进去,这块也一起看下。



protected final void refreshBeanFactory() throws BeansException {
// 如果存在 BeanFactory 则销毁 Bean 并关闭 BeanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 创建一个默认的 BeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
// 设置属性
customizeBeanFactory(beanFactory);
// 加载 Bean 信息
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}



其中会创建 BeanFactory 并加载 BeanDefinition。只不过我暂时没有断到,所以等后面遇到之后再详细介绍。



总结





本文简单介绍了 refresh 的流程,并介绍了前两个部分:



  1. prepareRefresh 准备上下文信息

  2. obtainFreshBeanFactory 初始化 BeanFactory



相关推荐





发布于: 2020 年 12 月 23 日阅读数: 10
用户头像

个人公众号:『 程序员小航 』 2020.07.30 加入

某不知名互联网公司 Java 程序员一枚。记录工作学习中的技术、开发及源码笔记;分享生活中的见闻感悟。

评论

发布
暂无评论
Spring 源码学习 09:refresh 大概流程