Spring源码十四:Spring生命周期

上一篇我们在Spring源码十三:非懒加载单例Bean中看到了Spring会在refresh方法中去调用我们的finishBeanFactoryInitialization方法去实例化,所有非懒加载器单例的bean。并实例化后的实例放到单例缓存中。到此我们refresh方法已经接近尾声。


Spring的生命周期

今天我们来看refresh方法中的最后一块逻辑:

@Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing. 1、初始化上下文信息,替换占位符、必要参数的校验prepareRefresh();// Tell the subclass to refresh the internal bean factory. 2、解析类Xml、初始化BeanFactoryConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 这一步主要是对初级容器的基础设计// Prepare the bean factory for use in this context. 	3、准备BeanFactory内容:prepareBeanFactory(beanFactory); // 对beanFactory容器的功能的扩展:try {// Allows post-processing of the bean factory in context subclasses. 4、扩展点加一:空实现,主要用于处理特殊Bean的后置处理器postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context. 	5、spring bean容器的后置处理器invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation. 	6、注册bean的后置处理器registerBeanPostProcessors(beanFactory);// Initialize message source for this context.	7、初始化消息源initMessageSource();// Initialize event multicaster for this context.	8、初始化事件广播器initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses. 9、扩展点加一:空实现;主要是在实例化之前做些bean初始化扩展onRefresh();// Check for listener beans and register them.	10、初始化监听器registerListeners();// Instantiate all remaining (non-lazy-init) singletons.// 11、实例化:非懒加载BeanfinishBeanFactoryInitialization(beanFactory);//!!!!!!!!!!!!  这里 这里 今天看这里  !!!!!!!!!!!//// Last step: publish corresponding event.// 12、初始化生命周期处理器,发布相应的事件通知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();}}}


finishRefresh

我们进入finishRefresh方法中去:

/*** Finish the refresh of this context, invoking the LifecycleProcessor's* onRefresh() method and publishing the* 完成应用上下文的刷新过程。此方法确保所有的资源和组件都已初始化,* 并发布相应的事件通知监听器* {@link org.springframework.context.event.ContextRefreshedEvent}.*/protected void finishRefresh() {// Clear context-level resource caches (such as ASM metadata from scanning).// 清除上下文级别的资源缓存clearResourceCaches();// Initialize lifecycle processor for this context.// 初始化化生命周期处理器initLifecycleProcessor();// Propagate refresh to lifecycle processor first.getLifecycleProcessor().onRefresh();// Publish the final event.// 发布已经刷新完成的事件publishEvent(new ContextRefreshedEvent(this));// Participate in LiveBeansView MBean, if active.// 将Application容器注册到LiveBeanView中LiveBeansView.registerApplicationContext(this);}

上述注释已经比较完整了,finishRefresh方法我们在整理总结下:主要是初始化和生命周期相关的一些组件,我们可以先到initLifecycleProcessor的方法,看下具体做了些什么?

/*** 初始化生命周期组件,如果beanFactory没有定义,* 则使用DefaultLifecycleProcessor初始化一个* 默认的生命周期组件,注册到容器中* Initialize the LifecycleProcessor.* Uses DefaultLifecycleProcessor if none defined in the context.* @see org.springframework.context.support.DefaultLifecycleProcessor*/protected void initLifecycleProcessor() {// 获取BeanFactory容器ConfigurableListableBeanFactory beanFactory = getBeanFactory();// 判断容器中是否存在lifecycleProcessorif (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {// 获取lifecycleProcessor,注册当前容器(AbstractApplicationContext)this.lifecycleProcessor =beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);if (logger.isTraceEnabled()) {logger.trace("Using LifecycleProcessor [" + this.lifecycleProcessor + "]");}}else {// 如果容器中没有lifecycleProcessor,则初始化DefaultLifecycleProcessorDefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();defaultProcessor.setBeanFactory(beanFactory);// 设置成员属性this.lifecycleProcessor = defaultProcessor;// 注册到Spring容器中beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);if (logger.isTraceEnabled()) {logger.trace("No '" + LIFECYCLE_PROCESSOR_BEAN_NAME + "' bean, using " +"[" + this.lifecycleProcessor.getClass().getSimpleName() + "]");}}}

可以看到在方法initLifecycleProcessor中,首先看下beanFactory中是否有名称为lifecycleProcessor的bean,存在直接获并复制给abstractApplicationContext的成员变量lifecycleProcessor,如果不存在,Spring框架会自动创建DefaultLifecycleProcessor类型的对象,赋值给成员变量,最后再注入到Spring容器中


DefaultLifecycleProcessor

进入DefaultLifecycleProcessor类中:

可以看到它主要实现了LifecycleProcessor, BeanFactoryAware这两个接口,我们来看下它的类图,如下所示:

看左边这块,DefaultLifecycleProcessor最终也是实现了Lifecycle接口与LifecycleProcessor接口我们展开看下这两个接口:

在Spring中,如果实现了接口Lifecycle,Spirng会在容器启动时,调用这些Bean中的start方法开启他们的生命周期,同样:如果在Spring容器关闭时也会调用stop方法来结束他们的生命周期。

而LifecycleProcessor在此基础上又新增了onRefrsh方法和onClose方法,主用来处理对应Bean的状态。

方法调用如下:


// 	// Propagate refresh to lifecycle processor first.//		getLifecycleProcessor().onRefresh();/*** 调用DefaultLifecycleProcessor.onRefresh()*/@Overridepublic void  onRefresh() {startBeans(true);this.running = true;}// Internal helpersprivate void startBeans(boolean autoStartupOnly) {// 1、获取所有lifecycle类型的BeanMap<String, Lifecycle> lifecycleBeans = getLifecycleBeans();Map<Integer, LifecycleGroup> phases = new HashMap<>();lifecycleBeans.forEach((beanName, bean) -> {if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {int phase = getPhase(bean);LifecycleGroup group = phases.get(phase);if (group == null) {group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);phases.put(phase, group);}group.add(beanName, bean);}});// 遍历 Map,排序后启动if (!phases.isEmpty()) {List<Integer> keys = new ArrayList<>(phases.keySet());Collections.sort(keys);for (Integer key : keys) {phases.get(key).start();}}}

可以看到在onRefresh方法中,像我们刚才分析的一样,就会从Spring容器中获取所有实现了Lifecycle接口的bean,然后调用start方法来开启它们的生命周期,也就是开启Spring的生命周期了。


publishEvent

接着往下看:

		// 发布已经刷新完成的事件publishEvent(new ContextRefreshedEvent(this));/*** Publish the given event to all listeners.* 发布事件,通知所有监听器* <p>Note: Listeners get initialized after the MessageSource, to be able* to access it within listener implementations. Thus, MessageSource* implementations cannot publish events.* @param event the event to publish (may be application-specific or a* standard framework event)*/@Overridepublic void publishEvent(ApplicationEvent event) {publishEvent(event, null);}/**** Publish the given event to all listeners.* 					用于将指定的事件发布给所有监听器* @param event the event to publish (may be an {@link ApplicationEvent}*                 	参数表示要发布的事件,可以是 ApplicationEvent* or a payload object to be turned into a {@link PayloadApplicationEvent})*               	或一个负载对象(将被转换为 PayloadApplicationEvent)。* 	 ** @param eventType the resolved event type, if known* @since 4.2*/protected void publishEvent(Object event, @Nullable ResolvableType eventType) {Assert.notNull(event, "Event must not be null");// Decorate event as an ApplicationEvent if necessary// 判断传入的 event 是否为 ApplicationEvent 的实例://		如果是,则直接赋值给 applicationEvent。//		如果不是,则将其包装为 PayloadApplicationEvent。ApplicationEvent applicationEvent;if (event instanceof ApplicationEvent) {applicationEvent = (ApplicationEvent) event;}else {applicationEvent = new PayloadApplicationEvent<>(this, event);// 如果 eventType 为空且事件被包装为 PayloadApplicationEvent,则从包装的事件中获取事件类型if (eventType == null) {eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();}}// 事件分发// Multicast right now if possible - or lazily once the multicaster is initialized:// 判断 earlyApplicationEvents 是否不为空// 如果不为空,说明广播器还未初始化,则将事件添加到 earlyApplicationEvents 队列中,等待广播器初始化后再分发。// 如果为空,说明广播器已初始化, 立即分发事件。if (this.earlyApplicationEvents != null) {this.earlyApplicationEvents.add(applicationEvent);}else {// 直接通过 getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);}// Publish event via parent context as well...// 如果当前上下文有父上下文 (this.parent 不为空),则同样向父上下文发布事件:if (this.parent != null) {//如果父上下文是 AbstractApplicationContext 的实例,则调用其 publishEvent 方法,同时传递事件和事件类型。// 如果不是,则直接调用父上下文的 publishEvent 方法。if (this.parent instanceof AbstractApplicationContext) {((AbstractApplicationContext) this.parent).publishEvent(event, eventType);}else {this.parent.publishEvent(event);}}}

根据我们两篇关于事件驱动的源码分析,事件ContextRefreshedEvent将会注册到广播器中,广播器会把该事件广播器相应的监听器去处理,这个事件相当于告诉Spring整个容器已经刷新了,也就说Spring容器ApplicationContext已经初始化完毕了。

总结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/867333.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android Camera2 集成人脸识别算法

这可能是全网唯一一篇介绍Android Camera2接口集成人脸算法的文章了~ 写在前面&#xff1a; 说起人脸识别&#xff0c;相信大家都不会感到陌生&#xff0c;在我们平时的工作生活中&#xff0c;人脸打卡、刷脸支付等等已经是应用的非常广泛了&#xff0c;人脸识别也给我们的生活…

数据可视化之智慧农业的窗口与引擎

在科技日新月异的今天,农业作为国民经济的基础产业,正逐步向智能化、数字化转型。农业为主题的数据可视化大屏看板,作为这一转型过程中的重要工具,不仅为农业管理者提供了全面、实时的农田信息,还促进了农业资源的优化配置和农业生产效率的提升。本文将深入探讨农业数据可…

Mysql-01-主从搭建

一、安装Mysql 下载 https://downloads.mysql.com/archives/community/ 安装 注意顺序 tar -xvf mysql-8.0.38-1.el9.x86_64.rpm-bundle.tar rpm -ivh mysql-community-common-8.0.38-1.el9.x86_64.rpm rpm -ivh mysql-community-client-plugins-8.0.38-1.el9.x86_64.r…

非NI GPIB卡与LabVIEW兼容性分析

在许多测试和测量应用中&#xff0c;通用接口总线&#xff08;GPIB&#xff09;是一种广泛使用的标准。尽管国家仪器公司&#xff08;NI&#xff09;提供的GPIB硬件和LabVIEW软件的组合被广泛接受和使用&#xff0c;但成本可能较高。因此&#xff0c;一些用户会考虑使用其他厂商…

蓄势高飞逐“新”空,卓翼飞思助力打造低空经济产业领域人才智库

2024年&#xff0c;“低空经济”首次写入政府工作报告&#xff0c;掀开新兴产业的崭新一页&#xff0c;而后迅速在全国各地呈现如火如荼的发展态势。这片蕴藏着巨大潜力和产业的蓝海&#xff0c;正蓄势聚能、乘势而起&#xff0c;站在发展的新风口上&#xff0c;面对新前景和新…

CorelDRAW2024新版本来咯!你的设计神助手

&#x1f389; 设计界的朋友们&#xff0c;注意啦&#xff01;你们的新宠——CorelDRAW 2024 来咯&#xff01; &#x1f31f; 一、设计神器再进化 亲爱的设计小伙伴们&#xff0c;有没有感觉每天与那些不配合的软件战斗&#xff0c;像是在打怪升级&#xff1f;&#x1f409; …

【matlab】智能优化算法——基准测试函数

智能优化算法的基准测试函数是用于评估和优化算法性能的一组标准问题。这些测试函数模拟了真实世界优化问题的不同方面&#xff0c;包括局部最小值、全局最优解、高维度、非线性、不连续等复杂性。以下是对智能优化算法基准测试函数的详细归纳&#xff1a; 测试函数的分类&…

数据结构初阶 遍历二叉树问题(一)

一. 链式二叉树的实现 1. 结构体代码 typedef int BTDateType; typedef struct BinaryTreeNode {BTDateType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right; }BTNode; 大概的图形是这样子 2. 增删查改 我们这里要明确的一点的 二叉树的增删查改是没有意…

springboot + mybatis 多数据源切换

参考的b站博主写的 配置文件: spring:datasource:db1:jdbc-url: jdbc:mysql://localhost:3306/interview_database?useUnicodetrue&characterEncodingutf-8&useSSLfalseusername: rootpassword: 12345driver-class-name: com.mysql.cj.jdbc.Driverdb2:jdbc-url: jdbc…

两年经验前端带你重学前端框架必会的ajax+node.js+webpack+git等技术的个人学习心得、作业及bug记录 Day1

黑马程序员前端AJAX入门到实战全套教程&#xff0c;包含学前端框架必会的&#xff08;ajaxnode.jswebpackgit&#xff09;&#xff0c;一套全覆盖 Day1 你好,我是Qiuner. 为帮助别人少走弯路和记录自己编程学习过程而写博客 这是我的 github https://github.com/Qiuner ⭐️ ​…

hdu物联网硬件实验1 小灯闪烁

物联网硬件基础实验报告 学院 班级 学号 姓名 日期 成绩 实验题目 配置环境小灯 实验目的 配置环境以及小灯闪烁 硬件原理 无 关键代码及注释 /* Blink The basic Energia example. Turns on an LED on for one second, then off for one sec…

Mysql-常见DML-DQL-语句语法用法总结

1、常见DML语句 1.1 INSERT语句 说明&#xff1a;将数据插入到数据库表中。 INSERT INTO table_name (column1, column2, ...) VALUES (value1, value2, ...); 实例&#xff1a;添加C罗信息到数据库表中 insert into employee (ID, name, gender, entrydate, age) values …

KUKA机器人维修保养消除报警

在使用KUKA机器人时&#xff0c;有时候会遇到示教器信息栏出现“基本检查到期”的信息&#xff0c;这就提示该机器到了基本保养时间了&#xff0c;需要进行保养。 一、报警信息和保养周期&#xff1a; KUKA机器人在使用超过一定保养周期后会出现“基本检查到期 / 中央手动保…

技术分析报告:StorageReview实验室打破π计算世界纪录

StorageReview实验室团队利用先进的计算系统&#xff0c;成功将π计算至202.112.290.000.000位&#xff0c;刷新了自己之前保持的105万亿位的世界纪录。这一成就突显了现代高性能计算&#xff08;HPC&#xff09;和精心设计的商用硬件平台的卓越能力。 关键技术组件&#xff1a…

【Unity navigation面板】

【Unity navigation面板】 Unity的Navigation面板是一个集成在Unity编辑器中的界面&#xff0c;它允许开发者对导航网格&#xff08;NavMesh&#xff09;进行配置和管理。 Unity Navigation面板的一些关键特性和功能&#xff1a; 导航网格代理&#xff08;NavMesh Agent&…

Python爬虫获取视频

验证电脑是否安装python 1.winr输入cmd 2.在黑窗口输入 python.exe 3.不是命令不存在就说明python环境安装完成 抓取快手视频 1.在phcharm应用中新建一个项目 3.新建一个python文件 4.选择python文件,随便起一个名字后按回车 5.安装requests pip install requests 6.寻找需要的…

Beats:使用 Filebeat 从 Python 应用程序中提取日志

本指南演示了如何从 Python 应用程序中提取日志并将其安全地传送到 Elasticsearch Service 部署中。你将设置 Filebeat 来监控具有标准 Elastic Common Schema (ECS) 格式字段的 JSON 结构日志文件&#xff0c;然后你将在 Kibana 中查看日志事件发生的实时可视化。虽然此示例使…

【Python实战因果推断】23_倾向分3

目录 Propensity Score Matching Inverse Propensity Weighting Propensity Score Matching 另一种控制倾向得分的常用方法是匹配估计法。这种方法搜索具有相似可观测特征的单位对&#xff0c;并比较接受干预与未接受干预的单位的结果。如果您有数据科学背景&#xff0c;您可…

Python使用matplotlib绘制图像时,中文图例或标题无法正常显示问题

Python使用matplotlib绘制图像时&#xff0c;中文图例或标题无法显示问题解决方法 一、问题描述二、解决方法 欢迎学习交流&#xff01; 邮箱&#xff1a; z…1…6.com 网站&#xff1a; https://zephyrhours.github.io/ 一、问题描述 Matplotlib库是Python中经常使用的绘图工…

如何注册微信公众号

如何注册微信公众号 如何注册一个微信公众号 &#x1f60a;&#x1f4f1;摘要引言正文内容1. 准备工作内容定位和受众群体公众号名称和头像 2. 网页注册流程第一步&#xff1a;访问微信公众平台第二步&#xff1a;选择账户注册类型第三步&#xff1a;填写基本信息第四步&#x…