文章目录
- 前言
- 所有初始化 Spring 容器的操作都会调用这个 refresh() 方法
- refresh() 方法 修改 active flag 为true
- 提供一个新入口
- 进入源码
- 对 refresh()中关键代码的解读
- prepareRefresh();
- ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
- prepareBeanFactory(beanFactory);
- postProcessBeanFactory(beanFactory);
- invokeBeanFactoryPostProcessors(beanFactory);
- registerBeanPostProcessors(beanFactory);
- initMessageSource();
- initApplicationEventMulticaster();
- onRefresh();
- registerListeners();
- finishBeanFactoryInitialization(beanFactory);
- finishRefresh();
- destroyBeans();
- cancelRefresh(ex);
- resetCommonCaches();
前言
体能状态先于精神状态,习惯先于决心,聚焦先于喜好
所有初始化 Spring 容器的操作都会调用这个 refresh() 方法
上一篇文章提到类这一点 2、Spring源码学习:认识加载 xml 文件的 ClassPathXmlApplicationContext
从其定义(org.springframework.context.ConfigurableApplicationContext.refresh() )来看,用于加载或者刷新来自 XML 文件、properties 文件 或者关系数据库的配置
是一个在开始阶段调用的方法,简单说,其负责加载的(non-lazy-init)单例 bean 要么全部成功,要么全部失败
refresh()的实现方法位于 org.springframework.context.support.AbstractApplicationContext
refresh() 方法 修改 active flag 为true
refresh() 内部调用方法 org.springframework.context.support.AbstractApplicationContext.prepareRefresh(
准备刷新上下文,设置开始时间和 active flag 未true
这个 active flag 是作为 是否需要刷新 applicatonContext 对象的标志
提供一个新入口
GenericApplicationContext
因为 在 Spring 容器加载的初期, refresh()方法都会被调用,本文开启了另一个入口
org.springframework.context.support.GenericApplicationContext
这个类可以为我们提供更灵活的配置,即手动去设置配置文件,以及手动调用 refresh() 方法
@Test
public void testRefresh() {
//org.springframework.context.support.GenericApplicationContext
GenericApplicationContext ctx = new GenericApplicationContext();
XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx);
//文件位于 src/main/resources 目录下
xmlReader.loadBeanDefinitions(new ClassPathResource("applicationContext.xml"));
PropertiesBeanDefinitionReader propReader = new PropertiesBeanDefinitionReader(ctx);
propReader.loadBeanDefinitions(new ClassPathResource("otherBeans.properties"));
//从这里进去源码
ctx.refresh();
//MyBean myBean = (MyBean) ctx.getBean("myBean");
}
refresh() 的 UML 关系图
用于表示 refresh() 方法与其他接口或类关系的UML 关系图
进入源码
refresh()
简单来说,Spring 创建一个webApplicationContext 之后,需要进行 refresh()动作,其中最主要的就是加载指定的 Spring 的配置文件。
并且将在这个方法中修改if (!cwac.isActive()) {
判断是是否激活标志 传送门
加载或者刷新持久化对配置信息,该配置可能是一个XML 文件,properties 文件,或者关系型数据库
由于这是一个启动阶段对方法,如果启动失败对化,所有已经被创建对单例bean都需要被销毁,以避免不稳定对资源出现.换句话说,这个方法被调用完毕后,要么所有的单例bean被加载到(上下文),要么一个都没有被加载.
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//刷新之前的准备工作,包括设置启动时间,是否激活标识位,初始化属性源(property source)配置
//这里将是否激活修改为 true
prepareRefresh();
// 通知子类刷新自己的 BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// 准备 beanFactory 供上下文使用(context,看具体实现的子类)
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
//允许子类对 beanFactory 进行 后续处理(post-processing)
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 调用上下文中注册的bean 工厂处理器
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 注册 使用拦截方式 对 bean 进行后续处理的b ean
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// 初始化 上下文 的 消息资源
initMessageSource();
// Initialize event multicaster for this context.
// 初始化 上下文 的事件广播器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 初始化子类上下文中被特殊定义的bean;Spring 提供的是一个空方法,供子类扩展
onRefresh();
// Check for listener beans and register them.
// 检查并注册事件监听器bean
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
// 实例化所有non-lazy-init(非延迟加载的) bean
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// 最后一步:发布相应的事件-上下文刷新工作完成了
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - "+"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
//销毁一ing被创建的单例 bean,避免不稳定资源的出现
destroyBeans();
// Reset 'active' flag.
//重置 ‘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...
// 重置 Spring's core 的缓存信息,因为我们可能不会再用到这些单例bean的元数据信息了
resetCommonCaches();
}
}
}
对 refresh()中关键代码的解读
prepareRefresh();
org.springframework.context.support.AbstractApplicationContext.prepareRefresh(
准备刷新上下文,设置开始时间和 active flag 以便于开始任何配置文件的初始化动作。
这里的 active flag 默认为 false,一般作为 新创建 webApplicationContext 对象是否刷新的标志 如 传送门
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}
// 初始化任何通配符匹配的文件,你可以任务该方法之后,操作系统相关、JVM相关信息都被加载了,准备的参数可以通过 getEnvironment() 来获取
initPropertySources();
//检测必须参数的非空性,通过 ConfigurablePropertyResolver#setRequiredProperties 设置
//debug发现,默认情况该方法没啥用-没有需要检测的从参数
getEnvironment().validateRequiredProperties();
//实例化LinkedHashSet,允许早期的 ApplicationEvents 集合在 multicaster 可用时被发布
this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
限于篇幅,单独写了一篇文章
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();