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…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error
在前端开发中,JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作(如 Promise、async/await 等),开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝(r…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现指南针功能
指南针功能是许多位置服务应用的基础功能之一。下面我将详细介绍如何在HarmonyOS 5中使用DevEco Studio实现指南针功能。 1. 开发环境准备 确保已安装DevEco Studio 3.1或更高版本确保项目使用的是HarmonyOS 5.0 SDK在项目的module.json5中配置必要的权限 2. 权限配置 在mo…...

从零开始了解数据采集(二十八)——制造业数字孪生
近年来,我国的工业领域正经历一场前所未有的数字化变革,从“双碳目标”到工业互联网平台的推广,国家政策和市场需求共同推动了制造业的升级。在这场变革中,数字孪生技术成为备受关注的关键工具,它不仅让企业“看见”设…...
数据库——redis
一、Redis 介绍 1. 概述 Redis(Remote Dictionary Server)是一个开源的、高性能的内存键值数据库系统,具有以下核心特点: 内存存储架构:数据主要存储在内存中,提供微秒级的读写响应 多数据结构支持&…...