首页 > 编程语言 >SpringBoot 源码 | applicationContext.refresh() 方法解析

SpringBoot 源码 | applicationContext.refresh() 方法解析

时间:2022-12-09 14:06:54浏览次数:61  
标签:applicationContext SpringBoot 初始化 refresh bean 源码 context 上下文 方法


@[TOC](SpringBoot 源码 | applicationContext.refresh() 方法解析)

SpringBoot

在 SpringBoot 启动流程中,主要的两个阶段是初始化 SpringApplication 对象以及 SpringApplication.run 方法执行的内容,在 SpringApplication.run 中的刷新容器 refreshContext 方法,可以说是最重要的方法,而点进去 refreshContext 方法的源码,可以看到真正主导的是 refresh 方法

refresh 方法

refreshContext 方法主要是刷新容器,下面我们来看一下 refreshContext 的源码,点击 SpringApplication.run 方法的 refreshContext 方法

SpringBoot 源码 | applicationContext.refresh() 方法解析_spring


跟进去 refresh(context)方法可以看到

SpringBoot 源码 | applicationContext.refresh() 方法解析_spring_02


继续跟进 applicationContext.refresh(),

SpringBoot 源码 | applicationContext.refresh() 方法解析_初始化_03


选择红框类路径就会看到 refresh 方法的详细内部方法了。

refresh 方法主要是刷新应用程序上下文,这里主要涉及到准备刷新上下文,调用上下文注册为 bean 的工厂处理器,初始化上下文的消息源,初始化特定上下文子类中的其他特殊 bean,检查监听器 bean 并注册,最后发布相应的事件并销毁已经创建的单例及重置 active 标志,整体的注解我都直接加在源码中了

@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

// Prepare this context for refreshing. 准备刷新上下文
prepareRefresh();

// Tell the subclass to refresh the internal bean factory. 告诉子类刷新内部bean工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// Prepare the bean factory for use in this context. 准备bean工厂以用于此上下文
prepareBeanFactory(beanFactory);

try {
// Allows post-processing of the bean factory in context subclasses. 允许在上下文子类中对bean工厂进行后置处理
postProcessBeanFactory(beanFactory);

StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
// Invoke factory processors registered as beans in the context. 调用上下文中注册为bean的工厂处理器
invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation. 注册拦截器bean创建的bean处理器
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();

// Initialize message source for this context. 初始化此上下文的消息源
initMessageSource();

// Initialize event multicaster for this context. 为此上下文初始化事件多播
initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses. 初始化特定上下文子类中的其他特殊bean
onRefresh();

// Check for listener beans and register them. 检查监听器bean并注册
registerListeners();

// Instantiate all remaining (non-lazy-init) singletons. 实例化所有剩余的(非懒惰初始化)单例
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. 销毁已创建的单例以避免悬空资源
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核心中的公共内省缓存,因为我们可能不再需要单例bean的元数据
resetCommonCaches();
contextRefresh.end();
}
}
}

下面我们继续看 refresh 方法内部子方法的源码

prepareRefresh

prepareRefresh 方法主要是准备上下文以进行刷新、设置其启动日期和活动标志以及执行属性源的任何初始化,源码注释如下

/**
* Prepare this context for refreshing, setting its startup date and
* active flag as well as performing any initialization of property sources.
*/
protected void prepareRefresh() {
// Switch to active. 切换到激活
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);

if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
}
else {
logger.debug("Refreshing " + getDisplayName());
}
}

// Initialize any placeholder property sources in the context environment. 初始化上下文环境中的任何占位符属性源
initPropertySources();

// Validate that all properties marked as required are resolvable:验证标记为需要的所有属性是否可解析
// see ConfigurablePropertyResolver#setRequiredProperties 主要看ConfigurablePropertyResolver#setRequiredProperties
getEnvironment().validateRequiredProperties();

// Store pre-refresh ApplicationListeners... 预刷新应用监听器
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// Reset local application listeners to pre-refresh state. 重置应用监听器为预刷新状态
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}

// Allow for the collection of early ApplicationEvents, 允许收集早期的应用事件在multicaster可用后一次性发布
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<>();
}

继续返回跟进 refresh 方法,在 prepareRefresh 之后是通知子类刷新内部 bean 工厂 obtainFreshBeanFactory

obtainFreshBeanFactory

obtainFreshBeanFactory 方法内部一共有两个方法 refreshBeanFactory 和 getBeanFactory,

SpringBoot 源码 | applicationContext.refresh() 方法解析_初始化_04


其中 refreshBeanFactory 什么也不做,主要是拥有一个内部 bean 工厂,并且信任调用者通过公共方法注册 bean 或者 BeanFactory’s,源码需要去看类 GenericApplicationContext 的 refreshBeanFactory 方法

SpringBoot 源码 | applicationContext.refresh() 方法解析_spring boot_05


下面我们再说 getBeanFactory 方法,获取 bean 工厂,源码注释是返回一个当前上下文的内部 bean 工厂

SpringBoot 源码 | applicationContext.refresh() 方法解析_java_06


继续向下看 refresh 方法,是 prepareBeanFactory 方法

prepareBeanFactory

prepareBeanFactory 方法是配置工厂标准的上下文特征,比如上下文类加载器、后置处理器

SpringBoot 源码 | applicationContext.refresh() 方法解析_spring boot_07


继续执行 refresh 方法,是 postProcessBeanFactory 方法

postProcessBeanFactory

postProcessBeanFactory 方法这里由于我们启动时的 WebApplicationType 是 SERVLET

SpringBoot 源码 | applicationContext.refresh() 方法解析_重置_08


所以这里我们选择如图,跟进去可以看到

SpringBoot 源码 | applicationContext.refresh() 方法解析_重置_09


为 bean 工厂添加后置处理器以及 registerWebApplicationScopes 为 bean 工厂注册特定的 web 作用域,之后继续执行

SpringBoot 源码 | applicationContext.refresh() 方法解析_spring_10


完成之后执行 refresh 方法内部的 invokeBeanFactoryPostProcessors 方法

invokeBeanFactoryPostProcessors

invokeBeanFactoryPostProcessors 方法主要负责调用 bean 工厂的后置处理器

SpringBoot 源码 | applicationContext.refresh() 方法解析_spring boot_11


继续执行是 registerBeanPostProcessors 方法,

registerBeanPostProcessors

registerBeanPostProcessors 方法主要是 Instantiate and register all BeanPostProcessor beans respecting explicit order if given 实例化并注册所有后置处理器 bean,如果给定,则遵循显式顺序

SpringBoot 源码 | applicationContext.refresh() 方法解析_spring boot_12


继续执行

initMessageSource

initMessageSource 方法主要是初始化应用上下文消息源,这个首先判断工厂类是否有 beanName 是 messageSource 的 bean

SpringBoot 源码 | applicationContext.refresh() 方法解析_java_13


有的通过 bean 工厂获取消息源

SpringBoot 源码 | applicationContext.refresh() 方法解析_初始化_14


没有的话 new 一个 DelegatingMessageSource 对象

initApplicationEventMulticaster

initApplicationEventMulticaster 方法主要是为上下文初始化事件多播,通过 bean 工厂获取 beanName 是 applicationEventMulticaster 的对象

SpringBoot 源码 | applicationContext.refresh() 方法解析_spring boot_15


如果没有的话就 new 一个 SimpleApplicationEventMulticaster 对象放回 bean 工厂

SpringBoot 源码 | applicationContext.refresh() 方法解析_重置_16


以应用上下文事件多播的 beanName 放入工厂

onRefresh

onRefresh 方法执行刷新,

SpringBoot 源码 | applicationContext.refresh() 方法解析_java_17


点进去可以看到

SpringBoot 源码 | applicationContext.refresh() 方法解析_重置_18


执行父类的 onRefresh 方法,创建 web 服务,createWebServer 方法主要是获取应用上下文创建 web 服务初始化 PropertySources

SpringBoot 源码 | applicationContext.refresh() 方法解析_重置_19

registerListeners

registerListeners 方法是检查并注册监听器,同时不影响其他监听器

SpringBoot 源码 | applicationContext.refresh() 方法解析_初始化_20


执行完成之后查看 getApplicationEventMulticaster 方法非 null

SpringBoot 源码 | applicationContext.refresh() 方法解析_spring boot_21

finishBeanFactoryInitialization

finishBeanFactoryInitialization 方法是实例化所有剩余的单例

SpringBoot 源码 | applicationContext.refresh() 方法解析_java_22


继续执行看到 finishRefresh 方法,也是最后一步

finishRefresh

finishRefresh 方法主要是发布事件,包括清除上下文资源缓存,为上下文初始化生命周期处理器,发布最终事件

SpringBoot 源码 | applicationContext.refresh() 方法解析_初始化_23


执行完成最后一步之后到 resetCommonCaches 方法

resetCommonCaches

resetCommonCaches 方法时重置 Spring 核心中的公共内省缓存,重置完成之后执行 contextRefresh.end 容器刷新结束方法,

SpringBoot 源码 | applicationContext.refresh() 方法解析_初始化_24


执行完成之后打印日志

SpringBoot 源码 | applicationContext.refresh() 方法解析_重置_25


启动结束,至此,SpringBoot 启动流程中的 refreshContext 方法功能执行完成

总结
在 SpringBoot 启动流程中,refreshContext 方法主要调用 refresh 方法,refresh 方法虽然执行步骤较多,加载的类也比较丰富,从准备刷新上下文到为上下文准备 bean 工厂及配置上下文类加载器,后置处理器到初始化上下文消息源、事件多播以及最后的检查监听器并注册以及实例化剩余的单例 bean,最后发布事件,重置 Spring 核心中的公共内省缓存,整体流程比较清晰,源码给的注释也很丰富,很方便对源码的学习。


标签:applicationContext,SpringBoot,初始化,refresh,bean,源码,context,上下文,方法
From: https://blog.51cto.com/u_10917175/5925117

相关文章