探究IOC容器刷新环节初始化前的预处理

目录

一、IOC容器的刷新环节快速回顾

二、初始化前的预处理prepareRefresh源码分析

三、初始化属性源

(一)GenericWebApplicationContext初始化属性源

(二)StaticWebApplicationContext初始化属性源

四、初始化早期事件集合


在很早之前我们单独写过一篇文章《分析SpringBoot启动配置原理》,具体可见:

分析SpringBoot启动配置原理icon-default.png?t=N7T8https://blog.csdn.net/xiaofeng10330111/article/details/130903779?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171664383116800186545975%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=171664383116800186545975&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-21-130903779-null-null.nonecase&utm_term=Spring&spm=1018.2226.3001.4450其中IOC容器的刷新环节可当重点分析,值得在读源码时进行深入分析,我们会从多个方向上再次进行分析回顾和学习。

一、IOC容器的刷新环节快速回顾

我们将AbstractApplicationContext的refresh方法源码提取并进行重点代码标注说明如下:

public abstract class AbstractApplicationContext implements ApplicationContext {@Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// 准备上下文环境,包括初始化工厂、后置处理器等prepareRefresh();// 创建并初始化 BeanFactoryConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// 设置 BeanFactory 的类加载器、资源加载器等prepareBeanFactory(beanFactory);try {// 允许子类对 BeanFactory 进行进一步的自定义处理postProcessBeanFactory(beanFactory);// 调用 BeanFactoryPostProcessors 进行后置处理invokeBeanFactoryPostProcessors(beanFactory);// 注册 BeanPostProcessors,用于对 Bean 实例进行后置处理registerBeanPostProcessors(beanFactory);// 初始化消息源initMessageSource();// 初始化事件广播器initApplicationEventMulticaster();// 初始化其他特殊 BeanonRefresh();// 注册关闭钩子registerListeners();// 初始化所有剩余的单例 BeanfinishBeanFactoryInitialization(beanFactory);// 完成上下文刷新finishRefresh();} catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// 销毁已创建的 Bean,关闭容器destroyBeans();// 重置容器刷新标志,允许再次刷新cancelRefresh(ex);// 把异常重新抛出,允许调用者处理throw ex;} finally {// 重置已注册的 JVM 关闭钩子resetCommonCaches();}}}
}

以上内容可多次翻看并理解,本文将关注初始化前的预处理prepareRefresh专项。

二、初始化前的预处理prepareRefresh源码分析

prepareRefresh() 方法的设计和实现体现了 Spring 容器在初始化之前做好了各种准备工作,以确保容器在刷新过程中能够顺利进行,并且应用程序能够正确地运行。我们直接展示源码如下:

protected void prepareRefresh() {this.startupDate = System.currentTimeMillis();this.closed.set(false);this.active.set(true);if (this.logger.isDebugEnabled()) {if (this.logger.isTraceEnabled()) {this.logger.trace("Refreshing " + this);} else {this.logger.debug("Refreshing " + this.getDisplayName());}}// 初始化属性源this.initPropertySources();// 验证必需的属性this.getEnvironment().validateRequiredProperties();// 复制早期应用程序监听器以供稍后使用if (this.earlyApplicationListeners == null) {this.earlyApplicationListeners = new LinkedHashSet(this.applicationListeners);} else {this.applicationListeners.clear();this.applicationListeners.addAll(this.earlyApplicationListeners);}// 初始化早期事件集合this.earlyApplicationEvents = new LinkedHashSet();
}

我们通过这个源码可见prepareRefresh() 方法的主要步骤,简要说明如下:

步骤说明
记录时间戳和设置状态标志记录容器的启动时间戳,并设置容器的状态标志,用于跟踪容器的状态。
日志记录根据日志级别记录容器的刷新过程,提供对容器启动过程的可视化和追踪。
属性源初始化和属性验证初始化属性源,以确保应用程序在后续的运行过程中能够正确地获取配置属性,并验证必需的属性是否已经设置。
处理早期应用程序监听器复制早期应用程序监听器以供稍后使用,以确保在容器刷新过程中能够保留早期监听器的设置。
初始化早期事件集合初始化一个早期事件集合,用于存储在容器刷新过程中产生的早期事件,以便后续处理。

针对其中的主要内容我们进行展开分析一下。

三、初始化属性源

直接展开源码分析:

 protected void initPropertySources() {}

无论是 AbstractRefreshableWebApplicationContextGenericWebApplicationContext 还是 StaticWebApplicationContext,它们都具有 initPropertySources() 方法的实现,用于初始化容器的属性源,确保容器能够正确地获取应用程序的配置信息,因此在创建这些应用程序上下文时都可能会调用这个方法。

(一)GenericWebApplicationContext初始化属性源

具体源码展示:

    protected void initPropertySources() {ConfigurableEnvironment env = this.getEnvironment();if (env instanceof ConfigurableWebEnvironment) {((ConfigurableWebEnvironment)env).initPropertySources(this.servletContext, (ServletConfig)null);}} ====================================================
package org.springframework.web.context;import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.lang.Nullable;public interface ConfigurableWebEnvironment extends ConfigurableEnvironment {void initPropertySources(@Nullable ServletContext var1, @Nullable ServletConfig var2);
}====================================================
package org.springframework.web.context.support;import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.jndi.JndiLocatorDelegate;
import org.springframework.jndi.JndiPropertySource;
import org.springframework.lang.Nullable;
import org.springframework.web.context.ConfigurableWebEnvironment;public class StandardServletEnvironment extends StandardEnvironment implements ConfigurableWebEnvironment {public static final String SERVLET_CONTEXT_PROPERTY_SOURCE_NAME = "servletContextInitParams";public static final String SERVLET_CONFIG_PROPERTY_SOURCE_NAME = "servletConfigInitParams";public static final String JNDI_PROPERTY_SOURCE_NAME = "jndiProperties";public StandardServletEnvironment() {}protected void customizePropertySources(MutablePropertySources propertySources) {propertySources.addLast(new PropertySource.StubPropertySource("servletConfigInitParams"));propertySources.addLast(new PropertySource.StubPropertySource("servletContextInitParams"));if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {propertySources.addLast(new JndiPropertySource("jndiProperties"));}super.customizePropertySources(propertySources);}public void initPropertySources(@Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {WebApplicationContextUtils.initServletPropertySources(this.getPropertySources(), servletContext, servletConfig);}
}

可以了解到 GenericWebApplicationContext 在初始化属性源时,会通过调用环境对象的 initPropertySources() 方法来实现。而环境对象通常是 StandardServletEnvironment 类的实例,它提供了对 Servlet 环境的特定支持,例如添加 Servlet 相关的属性源。

也即是说当我们在 Spring MVC 中创建一个基于 Java 配置的 Web 应用程序时,通常会使用 GenericWebApplicationContext 来管理应用程序上下文。在初始化容器时,GenericWebApplicationContext 会调用 initPropertySources() 方法来初始化属性源,这些属性源可能包括 Servlet 上下文参数、Servlet 配置参数以及 JNDI 属性等。这样,我们就能够在应用程序中方便地获取这些配置信息,例如通过 @Value 注解或 Environment 对象。

提到Environment 对象,可以扩展延读到:

重看Spring聚焦Environment分析-CSDN博客文章浏览阅读2.6k次,点赞17次,收藏12次。Environment模块在 Spring 中主要负责管理应用程序的配置和环境(定义为一组 profile配置文件)相关的信息,每个 profile 对应一个特定的应用程序部署环境,比如开发、测试、生产等。在这些 profile 中,可以包含各种属性,比如数据库连接信息、服务器端口、日志级别等。而对应的属性在 Spring 中被表示为键值对,其中键是属性的名称,值是属性的取值。属性可以通过不同的方式进行配置,比如在属性文件中、通过系统属性、操作系统环境变量等。https://blog.csdn.net/xiaofeng10330111/article/details/138143106?spm=1001.2014.3001.5501icon-default.png?t=N7T8https://blog.csdn.net/xiaofeng10330111/article/details/138143106?spm=1001.2014.3001.5501在 Spring Boot 应用程序启动时会自动加载 application.properties文件到 Environment 中。Spring Boot 的自动配置功能会根据这些配置属性来自动配置应用程序的各种组件和功能。

注意,虽然 initPropertySources() 方法在容器初始化时会起到一定的作用,但是在 Spring Boot 应用程序中,读取 application.properties 文件的功能主要是由 Spring Boot 框架本身负责的,它会将这些配置属性加载到 Environment 中,供整个应用程序使用。

(二)StaticWebApplicationContext初始化属性源

具体源码展示:

    protected void initPropertySources() {WebApplicationContextUtils.initServletPropertySources(this.getEnvironment().getPropertySources(), this.servletContext, this.servletConfig);}=======================================================public static void initServletPropertySources(MutablePropertySources sources, @Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {Assert.notNull(sources, "'propertySources' must not be null");String name = "servletContextInitParams";if (servletContext != null && sources.contains(name) && sources.get(name) instanceof PropertySource.StubPropertySource) {sources.replace(name, new ServletContextPropertySource(name, servletContext));}name = "servletConfigInitParams";if (servletConfig != null && sources.contains(name) && sources.get(name) instanceof PropertySource.StubPropertySource) {sources.replace(name, new ServletConfigPropertySource(name, servletConfig));}}

可以了解到 StaticWebApplicationContext 在初始化属性源时,会调用 WebApplicationContextUtils.initServletPropertySources() 方法来初始化 Servlet 相关的属性源。这些属性源通常包括了 Servlet 上下文参数和 Servlet 配置参数,它们是通过 ServletContextPropertySourceServletConfigPropertySource 来表示的。功能和常规的基本一致。

四、初始化早期事件集合

在上面的源码中可以直观的看到有个早期事件集合的初始化:

// 初始化早期事件集合
this.earlyApplicationEvents = new LinkedHashSet();

这段代码的作用是创建一个空的 LinkedHashSet 对象并赋值给 earlyApplicationEvents 变量,从而初始化了早期事件集合。

我们知道Spring框架是事件驱动的,它提供了一套事件机制用于在应用程序中处理各种事件。在容器的生命周期中,可能会产生各种事件,例如容器初始化完成事件、Bean初始化事件等。

在容器刷新过程中,一些事件可能会在容器完全初始化之前就已经发生。这些早期事件通常是在容器初始化的早期阶段触发的,例如在BeanFactory被创建之后但是Bean的实例化尚未开始之前。为了能够捕获并处理这些早期事件,Spring使用一个早期事件集合来存储这些事件。

在容器准备刷新之前在 prepareRefresh() 方法中会初始化早期事件集合,也就是上面的这个空的集合对象,主要用于后续能够添加早期事件。

也就是说,在容器刷新的过程中,如果产生了早期事件,就会将这些事件添加到早期事件集合中。这样,在容器刷新完成后,就可以从早期事件集合中获取这些事件,并进行后续的处理,例如执行事件监听器或发布事件通知。

一旦容器刷新完成,就可以对早期事件集合中的事件进行后续处理。这可能包括执行事件监听器、发布事件通知、执行一些初始化操作等。

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

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

相关文章

3.大模型高效微调PEFT

大模型高效微调(PEFT)技术 预训练模型的背景 预训练与微调:传统的微调方法通常涉及对整个预训练模型的参数进行再训练,以适应特定任务。这虽然有效,但计算成本高,且需要大量的标记数据。模型结构:像BERT或GPT这样的模型通常包含数亿甚至数十亿个参数,构成一个深层次的…

Qt——升级系列(Level Four):控件概述、QWidget 核心属性、按钮类控件

目录 控件概述 QWidget 核心属性 核心属性概览 enabled geometry windowTitle windowIcon windowOpacity cursor font toolTip focusPolicy styleSheet 按钮类控件 Push Button Radio Buttion Check Box Tool Button 控件概述 Widget 是 Qt 中的核⼼概念. 英⽂原义是 "…

西门子学习笔记11 - PTO脉冲指令的使用

1、使用指令前的设置 1、打开一个脉冲发生器,并启用 2、选择使用PTO(脉冲A和方向B) 3、硬件设置输出 4、这样前期的准备工作就完成了 2、指令的使用 1、添加指令CTRL_PTO 2、配置如下 3、方向控制程序如下 4、最后进行测试即可

C语言之存储类、作用域、生命周期、链接属性

一 :概念解析 1: 存储类 (1)存储类就是存储类型,就是描述C语言变量存储在什么地方 (2)内存有多种管理方法:栈、堆数据段、bss段、.text段......一个变量的存储类属性就是描述…

html--万年历

<!DOCTYPE html> <html lang"zh_CN"><head><meta http-equiv"Content-Type" content"text/html; charsetUTF-8" /><meta charset"utf-8" /><title>万年历</title><link rel"styles…

C语言 | Leetcode C语言题解之第142题环形链表II

题目&#xff1a; 题解&#xff1a; struct ListNode* detectCycle(struct ListNode* head) {struct ListNode *slow head, *fast head;while (fast ! NULL) {slow slow->next;if (fast->next NULL) {return NULL;}fast fast->next->next;if (fast slow) {s…

LLVM Cpu0 新后端9 objdump readelf

想好好熟悉一下llvm开发一个新后端都要干什么&#xff0c;于是参考了老师的系列文章&#xff1a; LLVM 后端实践笔记 代码在这里&#xff08;还没来得及准备&#xff0c;先用网盘暂存一下&#xff09;&#xff1a; 链接: https://pan.baidu.com/s/1yLAtXs9XwtyEzYSlDCSlqw?…

EE trade:如何在A股市场中有效设定止盈止损点

A股市场充满机遇和风险&#xff0c;很多投资者在这里实现了财富增长&#xff0c;也有投资者在这里遭受损失。如何在波动性较大的市场中&#xff0c;控制风险&#xff0c;保护利润和本金?止盈止损是关键。 什么是止盈止损? 止盈止损是指在交易中&#xff0c;根据预先设定的条…

如何稳定高效地进行 TiDB 数据导入导出?

对于在数据库行业中摸爬滚打多年的老鸟 DBA 来说&#xff0c;TiDB 可是一点也不陌生&#xff0c;作为 PingCAP 公司自主研发的真开源分布式数据库&#xff0c;其先进的设计理念以及丰富的生态工具&#xff0c;可算得上是业界自主创新和性能领先的代名词。 TiDB 是谁&#xff1…

MAVEN架构项目管理工具

1、什么是maven Maven是跨平台的项目管理工具。主要服务于基于Java平台的项目构建&#xff0c;依赖管理和项目信息管理。 2、maven的目标&#xff1a;Maven的主要目标是为了使开发人员在最短的时间内领会项目的所有状态 3、使用maven不需要考虑各个依赖的版本&#xff0c;因…

【将xml文件转yolov5训练数据txt标签文件】连classes.txt都可以生成

将xml文件转yolov5训练数据txt标签文件 前言一、代码解析 二、使用方法总结 前言 找遍全网&#xff0c;我觉得写得最详细的就是这个博文⇨将xml文件转yolov5训练数据txt标签文件 虽然我还是没有跑成功。那个正则表达式我不会改QWQ&#xff0c;但是不妨碍我会训练ai。 最终成功…

UE5中在地形中加入湖、河

系统水资产添加 前提步骤123 完成 前提 使用版本 UE5.0.3,使用插件为UE内置的Water和water Extras. 步骤 1 记得重启 2 增加地形&#xff0c;把<启用编辑图层>勾选 如果地形没有勾选上编辑图层&#xff0c;那么就会导致湖、河等水景象无法融入地形。 如果忘记勾选…

Hive知识体系保姆级教程

一. Hive概览 1.1 hive的简介 Hive是基于Hadoop的一个数据仓库工具&#xff0c;可以将结构化的数据文件映射为一张数据库表&#xff0c;并提供类SQL查询功能。 其本质是将SQL转换为MapReduce/Spark的任务进行运算&#xff0c;底层由HDFS来提供数据的存储&#xff0c;说白了h…

如何从 Android 图库中恢复误删除的照片

如果您正在阅读这篇文章&#xff0c;那么您肯定意外地从 Android 设备中删除了照片。并且您正在寻找一种简单的方法来恢复 Android 图库中已删除的照片。 从图库恢复已删除的照片 随着技术的进步&#xff0c;现在使用单个设备&#xff08;即 Android 手机&#xff09;&#xf…

使用贝塞尔曲线实现一个iOS时间轴

UI效果 实现的思路 就是通过贝塞尔曲线画出时间轴的圆环的路径&#xff0c;然后 使用CAShaper来渲染UI&#xff0c;再通过 animation.beginTime [cilrclLayer convertTime:CACurrentMediaTime() fromLayer:nil] circleTimeOffset 来设置每个圆环的动画开始时间&#xff0c; …

探索ChatGPT-4在解决化学知识问题上的研究与应用

1. 概述 近年来&#xff0c;人工智能的发展主要集中在 GPT-4 等大型语言模型上。2023 年 3 月发布的这一先进模型展示了利用广泛知识应对从化学研究到日常问题解决等复杂挑战的能力。也开始进行研究&#xff0c;对化学的各个领域&#xff0c;从化学键到有机化学和物理化学&…

【设计模式】行为型设计模式之 备忘录模式(快照模式)

介绍 备忘录应用场景明确并且有限&#xff0c;一般用来数据的防丢失、撤销和恢复。对大对象的备份和恢复&#xff0c;备忘录模式能有效的节省时间和空间开销。 定义 备忘录模式&#xff1a;也称为快照模式&#xff0c;在不违背封装原则的前提下&#xff0c;捕获一个对象的内…

BFS实现图的点的层次-java

加强对广度优先搜索的理解&#xff0c;其实就是主要的3个步骤&#xff0c;外加数组模拟单链表是基础&#xff0c;要搞懂。 目录 前言 一、图中点的层次 二、算法思路 1.广度优先遍历 2.算法思路 三、代码如下 1.代码如下&#xff08;示例&#xff09;&#xff1a; 2.读入…

探索基于订阅式的电视App:Android TV 端强大的开源视频播放器

探索基于订阅式的电视App&#xff1a;Android TV 端强大的开源视频播放器 在智能电视和流媒体日益普及的今天&#xff0c;一款强大的视频播放器是家庭娱乐的重要组成部分。正是这样一款为Android TV设计的开源视频播放器。本文将深入探讨电视盒子OSC的技术特点、使用方法以及其…

抛弃昂贵BI,企业仍可低成本实现数据分析

有的读者看完《BI工具选型不入坑&#xff0c;你要这么选》这篇文章就陷入迷茫了&#xff0c;我要做企业级数据分析&#xff0c;看过去各家产品都各有千秋&#xff0c;实在难以抉择&#xff0c;或者已经选了仍是纠结不已。 这里我抛出另一种思路&#xff1a;如果不用BI&#xf…