SpringBoot源码 | refreshContext方法解析

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: 本文主要讲述SpringBoot启动流程源码中的refreshContext()方法

SpringBoot

在SpringBoot启动流程中,主要的两个阶段是初始化SpringApplication对象以及SpringApplication.run方法执行的内容,今天主要细讲的是SpringApplication.run中的刷新容器refreshContext方法,refreshContext的源码如下

refreshContext源码

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

image.png看到refreshContext的方法内容

image.png

继续点击refresh方法可以看到,Refresh the underlying {@link ApplicationContext}也就是刷新底层的ApplicationContext

image.png

继续跟进去,这里要选择AbstractApplicationContext

image.png

这里我们看一下AbstractApplicationContext的注释,注释内容

Abstract implementation of the {@link org.springframework.context.ApplicationContext} interface. Doesn't mandate the type of storage used for configuration; simply implements common context functionality. Uses the Template Method design pattern,requiring concrete subclasses to implement abstract methods.翻译过来就是当前抽象类是ApplicationContext接口的抽象实现,不强制要求用于配置的存储类型;它只是实现了公共上下文功能,使用的是模板方法的设计模式,需要具体的子类来实现抽象方法。下面我们再看refresh方法

refresh方法

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

@Overridepublicvoidrefresh() throwsBeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
StartupStepcontextRefresh=this.applicationStartup.start("spring.context.refresh");
// Prepare this context for refreshing. 准备刷新上下文prepareRefresh();
// Tell the subclass to refresh the internal bean factory. 告诉子类刷新内部bean工厂ConfigurableListableBeanFactorybeanFactory=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);
StartupStepbeanPostProcess=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. 初始化特定上下文子类中的其他特殊beanonRefresh();
// 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 (BeansExceptionex) {
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. 将异常传播到调用方throwex;
        }
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.*/protectedvoidprepareRefresh() {
// 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#setRequiredPropertiesgetEnvironment().validateRequiredProperties();
// Store pre-refresh ApplicationListeners... 预刷新应用监听器if (this.earlyApplicationListeners==null) {
this.earlyApplicationListeners=newLinkedHashSet<>(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=newLinkedHashSet<>();
}

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

obtainFreshBeanFactory

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

image.png

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

image.png

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

image.png

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

prepareBeanFactory

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

image.png

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

postProcessBeanFactory

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

image.png

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

image.png

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

image.png

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

invokeBeanFactoryPostProcessors

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

image.png

继续执行是registerBeanPostProcessors方法,

registerBeanPostProcessors

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

image.png

继续执行

initMessageSource

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

image.png

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

image.png

没有的话new一个DelegatingMessageSource对象

initApplicationEventMulticaster

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

image.png

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

image.png

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

onRefresh

onRefresh方法执行刷新,

image.png

点进去可以看到

image.png

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

image.png

registerListeners

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

image.png

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

image.png

finishBeanFactoryInitialization

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

image.png

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

finishRefresh

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

image.png

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

resetCommonCaches

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

image.png

执行完成之后打印日志

image.png

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

总结

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


相关文章
|
5天前
|
数据可视化 项目管理
个人和团队都好用的年度复盘工具:看板与KPT方法解析
本文带你了解高效方法KPT复盘法(Keep、Problem、Try),结合看板工具,帮助你理清头绪,快速完成年度复盘。
38 7
个人和团队都好用的年度复盘工具:看板与KPT方法解析
|
12天前
|
Java 数据库连接 Maven
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
自动装配是现在面试中常考的一道面试题。本文基于最新的 SpringBoot 3.3.3 版本的源码来分析自动装配的原理,并在文未说明了SpringBoot2和SpringBoot3的自动装配源码中区别,以及面试回答的拿分核心话术。
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
|
12天前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
|
12天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。 结构型模式分为以下 7 种: • 代理模式 • 适配器模式 • 装饰者模式 • 桥接模式 • 外观模式 • 组合模式 • 享元模式
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
12天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是"将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。创建型模式分为5种:单例模式、工厂方法模式抽象工厂式、原型模式、建造者模式。
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
22天前
|
存储 JavaScript 前端开发
基于 SpringBoot 和 Vue 开发校园点餐订餐外卖跑腿Java源码
一个非常实用的校园外卖系统,基于 SpringBoot 和 Vue 的开发。这一系统源于黑马的外卖案例项目 经过站长的进一步改进和优化,提供了更丰富的功能和更高的可用性。 这个项目的架构设计非常有趣。虽然它采用了SpringBoot和Vue的组合,但并不是一个完全分离的项目。 前端视图通过JS的方式引入了Vue和Element UI,既能利用Vue的快速开发优势,
107 13
|
13天前
|
安全 搜索推荐 数据挖掘
陪玩系统源码开发流程解析,成品陪玩系统源码的优点
我们自主开发的多客陪玩系统源码,整合了市面上主流陪玩APP功能,支持二次开发。该系统适用于线上游戏陪玩、语音视频聊天、心理咨询等场景,提供用户注册管理、陪玩者资料库、预约匹配、实时通讯、支付结算、安全隐私保护、客户服务及数据分析等功能,打造综合性社交平台。随着互联网技术发展,陪玩系统正成为游戏爱好者的新宠,改变游戏体验并带来新的商业模式。
|
2月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
87 2
|
3月前
|
缓存 Java 程序员
Map - LinkedHashSet&Map源码解析
Map - LinkedHashSet&Map源码解析
87 0
|
3月前
|
算法 Java 容器
Map - HashSet & HashMap 源码解析
Map - HashSet & HashMap 源码解析
68 0

推荐镜像

更多