Spring上下文生命周期
基于入口来分析
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;@Configuration
@ComponentScan
public class MainConfig {public static void main(String[] args) {//1.创建spring上下文AnnotationConfigApplicationContext configApplicationContext = new AnnotationConfigApplicationContext();//2.上下文中注册beanconfigApplicationContext.register(MainConfig.class);//3.刷新spring上下文,内部会启动spring上下文configApplicationContext.refresh();//4.关闭spring上下文System.out.println("stop ok!");configApplicationContext.close();}
}
创建Spring应用上下文
AnnotatedBeanDefinitionReader
用来读取及注册通过注解方式定义的bean
ClassPathBeanDefinitionScanner
bean定义扫描器,可以扫描包中的类,对满足条件的类,会将其注册到spring容器中
ConfigurationClassPostProcessor
负责所有bean的注册,如果想看bean注册源码的,可以在其postProcessBeanDefinitionRegistry方法中设置断点。处理如下注解
- @Configuration
- @Component
- @PropertySource
- @PropertySources
- @ComponentScan
- @ComponentScans
- @Import
- @ImportResource
- @Bean
org.springframework.context.annotation.AnnotatedBeanDefinitionReader#registerBean(java.lang.Class<?>)
AutowiredAnnotationBeanPostProcessor
负责处理@Autowire注解
CommonAnnotationBeanPostProcessor
负责处理@Resource注解
EventListenerMethodProcessor
负责处理@EventListener标注的方法,即事件处理器
DefaultEventListenerFactory
负责将@EventListener标注的方法包装为ApplicationListener对象
AbstractApplicationContext#refresh
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");/*** 阶段2:Spring应用上下文启动准备阶段* 1、切换到活动状态* 2、初始化PropertySource,留给子类去实现的,可以在这个方法中扩展属性配置信息,丢到this.environment中* 3、验证环境配置中是否包含必须的配置参数信息,* 4、存储存放早期的事件监听器、应用程序事件*/prepareRefresh();/*** 阶段3:BeanFactory创建阶段* 1、刷新BeanFactory,由子类实现* 2、返回spring上下文中创建好的BeanFacotry*/ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();/*** 阶段4:BeanFactory准备阶段* 1、设置类加载器* 2、设置SPEL表达式解析器:BeanExpressionResolver* 3、设置属性编辑注册器:PropertyEditorRegistrar* 4、添加BeanPostProcessor:ApplicationContextAwareProcessor,当自定义Bean实现了EnvironmentAware等接口时,进行接口方法回调赋值* 5、注册依赖注入的时候查找的对象:BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext* 6、添加BeanPostProcessor:ApplicationListenerDetector,处理自定义的事件监听器* 7、添加LoadTimeWeaver* 8、将Environment注册到spring容器,对应的bena名称是environment* 9、将系统属性注册到spring容器,对应的bean名称是systemProperties,对应 --> System.getProperties()启动参数,如-D参数=值* 10、将系统环境变量配置信息注入到spring容器,对应的bean名称是systemEnvironment,对应 --> System.getenv()获取环境变量信息的* 11、添加Bean:applicationStartup*/prepareBeanFactory(beanFactory);try {/*** 阶段5:BeanFactory后置处理阶段:允许在上下文子类中对 Bean 工厂进行后处理。* 此时beanFactory已经创建好了,但是容器中的bean还没有被实例化,子类可以实现这个方法,可以对BeanFactory做一些特殊的配置,* 比如可以添加一些自定义BeanPostProcessor等等,主要是留给子类去扩展的。*/postProcessBeanFactory(beanFactory);StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");/*** 阶段6:BeanFactory注册BeanPostProcessor阶段* 主要是从spring容器中找到BeanFactoryPostProcessor接口的所有实现类,然后调用,完成所有bean注册的功能,* 注意是bean注册,即将bean的定义信息转换为BeanDefinition对象,然后注册到spring容器中,此时bean还未被实例化。* 1、调用BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry(依次从传的addBeanFactoryPostProcessor>实现了PriorityOrdered->Order->其他)* spring中所有bean的注册都会在此阶段完成,按照规范,所有bean的注册必须在此阶段进行,其他阶段不要再进行bean的注册。* 2、调用BeanFactoryPostProcessor.postProcessBeanFactory* 到这个阶段的时候,spring容器已经完成了所有bean的注册,这个阶段中你可以对BeanFactory中的一些信息进行修改,比如修改阶段1中一些bean的定义信息,修改BeanFactory的一些配置等等*/invokeBeanFactoryPostProcessors(beanFactory);/*** 阶段7:注册BeanPostProcessor(bean后置处理器)* 这个阶段会遍历spring容器bean定义列表,把所有实现了BeanPostProcessor接口的bean撸出来,然后将他们添加到spring容器的BeanPostProcessor列表中。* 本质上就是执行:beanFactory.addBeanPostProcessor(postProcessor);* 1、注册了BeanPostProcessorChecker* 2、注册实现了BeanPostProcessor接口的Bean* 3、注册了ApplicationListenerDetector*/registerBeanPostProcessors(beanFactory);beanPostProcess.end();/*** 阶段8:初始化内建Bean:MessageSource是用来处理国际化的* 1、注册bean messageSource(可自定义)*/initMessageSource();/*** 阶段9:初始化内建Bean:Spring事件广播器* 1、注册bean applicationEventMulticaster(可自定义),也可自定义Executor*/initApplicationEventMulticaster();/*** 阶段10:Spring应用上下文刷新阶段,由子类实现初始化其他特殊 bean。*/onRefresh();/*** 阶段11:Spring事件监听器注册阶段,注册事件监听器到事件广播器中* 1、先注册静态指定的侦听器,即将spring上下文中添加的事件监听器,添加到事件广播器(ApplicationEventMulticaster阶段9)* 2、将spring容器中定义的事件监听器,添加到事件广播器(ApplicationEventMulticaster)中* 3、发布早期的事件*/registerListeners();/*** 阶段12:实例化所有剩余的(非lazy init)单例bean,不包需要延迟实例化的bean* 1、初始化conversionService转换服务* 2、添加${}表达式解析器,EmbeddedValueResolver* 3、早一些实例化LoadTimeWeaverAware类的Bean* 4、冻结所有bean定义,表示已注册的bean定义不会被进一步修改或后处理。这允许工厂主动缓存bean定义元数据。* 5、实例化所有单例bean(不包含需延迟实例化的bean),通常scope=singleton的bean都会在下面这个方法中完成初始化。beanFactory.preInstantiateSingletons();* 以下是beanFactory.preInstantiateSingletons();* 1、循环遍历beanNames列表,完成所有单例bean的实例化工作,这个循环完成之后,所有单例bean已经实例化完毕了,被放在spring容器缓存起来了。* 2、触发所有 bean 的初始化后回调...调用Bean实现了SmartInitializingSingleton接口的afterSingletonsInstantiated方法*/finishBeanFactoryInitialization(beanFactory);/*** 阶段13:刷新完成阶段,最后一步:发布相应的事件。* 1、清理一些资源缓存* 2、为此上下文初始化生命周期处理器,注册bena lifecycleProcessor spring应用上下文的生命周期处理器(可自定义)* 3、首先将刷新传播到生命周期处理器,执行LifecycleProcessor.onRefresh():从容器中找到所有实现Lifecycle接口的bean,然后调用他们的start方法。* 4、发布ContextRefreshedEvent事件,想在这个阶段做点事情的,可以监听这个事件。*/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.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();}}}
Spring应用上下文关闭阶段
protected void doClose() {// 判断是不是需要关闭(active为tue的时候,才能关闭,并用cas确保并发情况下只能有一个执行成功)if (this.active.get() && this.closed.compareAndSet(false, true)) {if (logger.isDebugEnabled()) {logger.debug("Closing " + this);}if (!NativeDetector.inNativeImage()) {LiveBeansView.unregisterApplicationContext(this);}try {// 发布关闭事件ContextClosedEventpublishEvent(new ContextClosedEvent(this));}catch (Throwable ex) {logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);}// 执行生命周期处理器LifecycleProcessor.onClose():从容器中找到所有实现Lifecycle接口的bean,然后调用他们的stop方法。if (this.lifecycleProcessor != null) {try {this.lifecycleProcessor.onClose();}catch (Throwable ex) {logger.warn("Exception thrown from LifecycleProcessor on context close", ex);}}// 销毁上下文的BeanFactory中所有缓存的单例destroyBeans();// 关闭BeanFactory本身closeBeanFactory();// 就给子类去扩展的onClose();// 恢复事件监听器列表至刷新之前的状态,即将早期的事件监听器还原if (this.earlyApplicationListeners != null) {this.applicationListeners.clear();this.applicationListeners.addAll(this.earlyApplicationListeners);}// 标记活动状态为:falsethis.active.set(false);}
}
相关文章:

Spring上下文生命周期
基于入口来分析 import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration;Configuration ComponentScan public cl…...

GitHub 标星 15w,如何用 Python 实现所有算法?
学会了 Python 基础知识,想进阶一下,那就来点算法吧!毕竟编程语言只是工具,结构算法才是灵魂。 新手如何入门 Python 算法? 几位印度小哥在 GitHub 上建了一个各种 Python 算法的新手入门大全。从原理到代码…...

LeetCode 700. 二叉搜索树中的搜索
LeetCode 700. 二叉搜索树中的搜索 难度:easy\color{Green}{easy}easy 难度:middle\color{orange}{middle}middle 难度:hard\color{red}{hard}hard 题目描述 给定二叉搜索树(BST)的根节点 rootrootroot 和一个整数值…...

【数据结构】树与二叉树
目录 1、树的概念及结构 1.1、概念 1、树的特点 2、树与非树 1.2、概念 (重要) 1.3、树的表示形式 2、二叉树(重点) 2.1、概念 2.2、二叉树的特点 2.3、两种特殊的二叉树 1、满二叉树 2、完全二叉树 2.4、二叉树的性…...

Stress压力工具的部署及使用
Stress压力工具的部署及使用 下载地址:wget https://fossies.org/linux/privat/old/stress-1.0.5.tar.gz 1.部署 进入目录执行./autogen.sh [rootiZ2ze1pj93eyq389c2ppi5Z stress-1.0.5]# ./autogen.sh ps:如果执行过程中缺包,安装对应的…...
[蓝桥杯 2020 省 AB3] 乘法表
题目描述九九乘法表是学习乘法时必须要掌握的。在不同进制数下,需要不同的乘法表。例如, 四进制下的乘法表如下所示:1*11 2*12 2*210 3*13 3*212 3*321请注意,乘法表中两个数相乘的顺序必须为样例中所示的顺序,不能随意交换两个乘…...
Python基础知识
基础知识 基础知识包括输入输出、变量、数据类型、表达式、运算符这5个方面。 1.输入输出 Python有很多函数,后面我们会细讲,但这里先将两个最基本的函数:输入和输出。 输出函数print(),在前面我们已经用过了,语法…...
FME案例实战教程:聚焦实战应用,摆脱思路束缚,您值得拥有
一、教程链接(一)FME案例实战教程链接1.FME案例实战教程(完整版) ☚强烈推荐☚2.FME案例实战教程(A组)3.FME案例实战教程(B组)4.FME案例实战教程(C组)&#…...

【JavaScript】根据元素内容遍历元素的方案
▒ 目录 ▒🛫 导读需求1️⃣ jQuery2️⃣ XPATH(document.evaluate)3️⃣ 原生js(querySelectorAll & Array)🛬 文章小结📖 参考资料🛫 导读 需求 因业务需要,根据元…...

kafka全解
目录Kafka概述定义消息队列目录结构分析传统消息队列的应用场景消息队列的两种模式点对点模式发布/订阅模式Kafka基础架构Kafka快速入门安装部署集群规划集群部署集群启停脚本Kafka命令行操作Kafka基础架构主题命令行操作生产者命令行操作消费者命令行操作kafka可视化工具Kafka…...

(三)随处可见的LED广告屏是怎么工作的呢?接入GUI
续上文,本篇我们将尝试接入一个GUI来控制点阵屏。在前两篇中,我们相继介绍了点阵屏的控制原理,以及如何让点阵屏按照我们所想的进行显示。本篇将在此基础上接入一个GUI,使点阵屏的控制更加优雅。限于阅读体验和展示效果࿰…...
线程池简介
线程池 线程池(英语:thread pool):一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时…...

大数据面试题集锦-Hadoop面试题(四)-YARN
你准备好面试了吗?这里有一些面试中可能会问到的问题以及相对应的答案。如果你需要更多的面试经验和面试题,关注一下"张飞的猪大数据分享"吧,公众号会不定时的分享相关的知识和资料。 文章目录1、为什么会产生 yarn,它解决了什么问题…...

Python---time模块
专栏:python 个人主页:HaiFan. 专栏简介:Python在学,希望能够得到各位的支持!!! time模块前言时间戳time.time()将时间戳转换成字符串time.ctime()将时间戳转换为元组time.localtime(时间戳)将元…...

坚鹏:学习贯彻二十大精神 解码共同富裕之道(面向银行)
学习贯彻二十大精神 解码共同富裕之道课程背景: 很多银行从业人员存在以下问题:不知道如何准确解读二十大精神?不清楚共同富裕相关政策要求?不知道如何有效推动共同富裕? 课程特色:有实战案例有…...
python查看程序的cpu和内存资源占用情况
1.获取线程消耗的内存 :线程内存使用的概念没有明确定义。线程共享它们的内存。唯一真正的线程本地内存是它的调用堆栈,除非您认真地递归地做一些事情,否则这不是有趣的部分。 2.获取进程消耗的内存 3.获取程序消耗的内存 mprof run endpoint.py 4.查看…...

番外10:使用ADS对射频功率放大器进行非线性测试2(使用带宽20MHz的64QAM信号进行ACLR、EVM、CCDF测试)
番外10:使用ADS对射频功率放大器进行非线性测试2(使用带宽20MHz的64QAM信号进行ACLR、EVM、CCDF测试) 1、基本理论 功率放大器的非线性性能十分重要,特别是对于当前广泛使用的移动设备。由于其各种复杂的信号调制,功…...

Ubuntu搭建maven私服
1.安装JDK8 已经是JDK8的需要配置环境变量,如果是更高版本的JDK则需要修改nexus配置文件 2.下载nexus安装包 百度网盘下载:链接:https://pan.baidu.com/s/1DfKqql8tZNQXEBxAEH7UyA 提取码:hx4p安装到有磁盘的目录如下所示&…...

【JavaWeb】Servlet基础
文章目录1.Tomcat服务器安装注意事项2.编写WebApp3.BS系统角色和协议4.模拟Servlet4.1模拟sun公司4.2模拟Tomcat服务器4.3模拟WebApp开发者5.开发一个带有Servlet的WebApp5.1创建一个名为crm的项目5.2 在项目中创建一个名为WEB-INF的文件(必须)5.3在WEB-…...
pinia + pinia-plugin-persistedstate + 组合式API 写法,持久化失效问题
持久化失效卡了一天的问题安装使用就不多说了,主要是针对持久化失效的几个问题说明和解决方法首先是组合式写法,配置持久化export const useUserStore defineStore(user, () > {},{persist: true} )defineStore 第三个参数,具体可以看 p…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...

Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...

AI语音助手的Python实现
引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...

数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !
我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...
Leetcode33( 搜索旋转排序数组)
题目表述 整数数组 nums 按升序排列,数组中的值 互不相同 。 在传递给函数之前,nums 在预先未知的某个下标 k(0 < k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...
全面解析数据库:从基础概念到前沿应用
在数字化时代,数据已成为企业和社会发展的核心资产,而数据库作为存储、管理和处理数据的关键工具,在各个领域发挥着举足轻重的作用。从电商平台的商品信息管理,到社交网络的用户数据存储,再到金融行业的交易记录处理&a…...

Selenium 查找页面元素的方式
Selenium 查找页面元素的方式 Selenium 提供了多种方法来查找网页中的元素,以下是主要的定位方式: 基本定位方式 通过ID定位 driver.find_element(By.ID, "element_id")通过Name定位 driver.find_element(By.NAME, "element_name"…...

C#中用于控制自定义特性(Attribute)
我们来详细解释一下 [AttributeUsage(AttributeTargets.Class, AllowMultiple false, Inherited false)] 这个 C# 属性。 在 C# 中,Attribute(特性)是一种用于向程序元素(如类、方法、属性等)添加元数据的机制。Attr…...