专题四:Spring源码初始化环境与BeanFactory

上文我们通过new ClassPathXmlApplicationContext("applicationContext.xml");这段代码看了下Spring是如何将Xml里面内容注入到Java对象中,并通过context.getBean("jmUser");方式获得了一个对象实例,而避开使用new 来耦合。今天我们就来看看Spring是如何做到的呢?

上图是AbstractApplicationContext的类图,dedug跟踪这段代码

 new ClassPathXmlApplicationContext("applicationContext.xml");

ClassPathXmlApplicationContext构造方法

/*** 根据xml路径,创建一个ClassPathXmlApplicationContext实例* Create a new ClassPathXmlApplicationContext with the given parent,* loading the definitions from the given XML files.* @param configLocations array of resource locations* @param refresh whether to automatically refresh the context,* loading all bean definitions and creating all singletons.* Alternatively, call refresh manually after further configuring the context.* @param parent the parent context* @throws BeansException if context creation failed* @see #refresh()*/public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)throws BeansException {// 调用父类构造方法,主要是初始化环境变量相关信息,核心代码在 AbstractApplicationContext 类中super(parent);// 设置配置文件的位置 ApplicationContext的实现可能会使用默认的配置文件位置。setConfigLocations(configLocations);// 默认构造trueif (refresh) {// 进入核心方法refresh();}}

1、初始化环境变量相关信息

发现最终进入

	/*** Create a new AbstractApplicationContext with no parent.* 创建一个没有父容器的AbstractApplicationContext的实例*/public AbstractApplicationContext() {//  返回一个 PathMatchingResourcePatternResolver(this)实例this.resourcePatternResolver = getResourcePatternResolver();}/*** Create a new AbstractApplicationContext with the given parent context.* @param parent the parent context*/public AbstractApplicationContext(@Nullable ApplicationContext parent) {this();// 将父容器复制给成员变量 parent,如果parent不为空且属于ConfigurableEnvironment类型则合并环境setParent(parent);}

2、设置配置文件的位置

/*** Set the config locations for this application context.* <p>If not set, the implementation may use a default as appropriate.* 配置了配置文件的位置* 如果未设置配置位置,某些ApplicationContext的实现可能会使用默认的配置文件位置。* 例如,ClassPathXmlApplicationContext如果没有指定配置位置,会尝试查找类路径下的applicationContext.xml文件。*/public void setConfigLocations(@Nullable String... locations) {if (locations != null) {Assert.noNullElements(locations, "Config locations must not be null");this.configLocations = new String[locations.length];for (int i = 0; i < locations.length; i++) {
//				getEnvironment().resolveRequiredPlaceholders(path),从路径中解析展位福${}参数this.configLocations[i] = resolvePath(locations[i]).trim();}}else {this.configLocations = null;}}/*** Resolve the given path, replacing placeholders with corresponding* environment property values if necessary. Applied to config locations.* @param path the original file path* @return the resolved file path* @see org.springframework.core.env.Environment#resolveRequiredPlaceholders(String)*/protected String resolvePath(String path) {return getEnvironment().resolveRequiredPlaceholders(path);}public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {return this.propertyResolver.resolveRequiredPlaceholders(text);}

3、进入refresh方法

public 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);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();}}}

整个流程可以分为以下几个主要步骤:

  1. 初始化上下文环境信息。
  2. 解析XML配置文件,创建并初始化BeanFactory
  3. 设置BeanFactory的类加载器,注册一些默认的环境Bean。
  4. 提供扩展点用于对BeanFactory进行进一步的定制。
  5. 调用BeanFactory的后置处理器。
  6. 注册Bean的后置处理器。
  7. 初始化消息源,用于国际化支持。
  8. 初始化事件广播器,用于发布事件。
  9. 提供扩展点用于在刷新上下文时做一些特殊的初始化。
  10. 检查并注册监听器Bean。
  11. 实例化所有剩余的单例Bean(非懒加载)。
  12. 发布相应的事件通知,表示上下文刷新完成。

步骤概览

1. prepareRefresh()
prepareRefresh();

prepareRefresh()方法用于初始化上下文环境信息,包括设置启动时间、活动状态等基本属性。它确保在刷新过程中,应用上下文处于正确的状态。

2. obtainFreshBeanFactory()
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

该方法解析XML配置文件,创建并初始化BeanFactory,并载入Bean定义。它是Spring应用上下文初始化的关键步骤之一。

3. prepareBeanFactory(beanFactory)
prepareBeanFactory(beanFactory);

此步骤设置BeanFactory的类加载器,并注册一些默认的环境Bean,如类加载器、表达式解析器等。它确保BeanFactory在上下文中能够正确工作。

4. postProcessBeanFactory(beanFactory)
postProcessBeanFactory(beanFactory);

这是一个扩展点,通常为空实现。开发者可以在子类中重写该方法,对BeanFactory进行进一步的定制,如添加额外的Bean定义或修改现有的Bean定义。

5. invokeBeanFactoryPostProcessors(beanFactory)
invokeBeanFactoryPostProcessors(beanFactory);

该方法调用BeanFactory的后置处理器,这些处理器可以在Bean实例化之前对Bean定义进行修改或增加新的Bean定义。

6. registerBeanPostProcessors(beanFactory)
registerBeanPostProcessors(beanFactory);

在此步骤中,Spring注册Bean的后置处理器,这些处理器会在Bean的创建过程中拦截并进行处理,如执行依赖注入和初始化回调等。

7. initMessageSource()
initMessageSource();

该方法初始化消息源,用于支持国际化(i18n)。它允许应用程序根据用户的语言环境显示不同的消息。

8. initApplicationEventMulticaster()
initApplicationEventMulticaster();

Spring使用事件广播器来发布和监听应用程序事件。该方法初始化事件广播器,确保事件能够在应用上下文中正确传播。

9. onRefresh()
onRefresh();

这是另一个扩展点,通常为空实现。开发者可以在子类中重写该方法,在刷新上下文时执行一些特殊的初始化操作。

10. registerListeners()
registerListeners();

该方法检查并注册监听器Bean,用于监听和处理应用程序事件。

11. finishBeanFactoryInitialization(beanFactory)
finishBeanFactoryInitialization(beanFactory);

此步骤实例化所有剩余的单例Bean(非懒加载)。它确保所有Bean都已准备就绪,可以在应用程序中使用。

12. finishRefresh()
finishRefresh();

最后,Spring发布相应的事件通知,表示上下文刷新已完成。此步骤通常包括发布ContextRefreshedEvent事件,通知所有监听器上下文已刷新。

总结

本章主要通过断点源码,一步步跟踪到refresh方法,然后整体跟踪了refresh的具体步骤,每一步大概干了什么内容,后面我们将一个一个方法深入讨论,具体做了什么?预留了什么扩展点。我们在开发中怎么去使用这些扩展点。以及后面SpringBoot和SpringCloud是怎样利用这些扩展点给我么提供开箱即用的功能的。

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

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

相关文章

【TB作品】智能台灯控制器,ATMEGA128单片机,Proteus仿真

题目 8 &#xff1a;智能台灯控制器 基于单片机设计智能台灯控制器&#xff0c;要求可以调节 LED 灯的亮度&#xff0c;实现定时开启与关闭&#xff0c; 根据光照自动开启与关闭功能。 具体要求如下&#xff1a; &#xff08;1&#xff09;通过 PWM 功能调节 LED 灯亮度&#x…

娱乐圈发生震动,AI大模型技术已经取代了SNH48的小偶像?

自2023年以来&#xff0c;全球都被包裹在AI的惊天大潮之中&#xff0c;所有行业都在主动或被动地迎接改变。目前&#xff0c;各行业已经有大量公司正在把AI作为自身发展的最佳路径。其中&#xff0c;娱乐行业作为最被人们熟知的行业也在面对AI的发展时&#xff0c;发生着巨大变…

GMSB文章九:微生物的相关关系组间波动

欢迎大家关注全网生信学习者系列&#xff1a; WX公zhong号&#xff1a;生信学习者Xiao hong书&#xff1a;生信学习者知hu&#xff1a;生信学习者CDSN&#xff1a;生信学习者2 介绍 计算配对微生物在组间的相关关系波动情况进而评估不同分组的微生物状态。secom_linear 函数…

线性表与顺序存储结构(下)

前言 接上文&#xff08;线性表与顺序存储结构&#xff08;上&#xff09;&#xff09;。 这些顺序存储结构的方法在顺序表上下卷中已经提到过&#xff0c;但是有些许不同&#xff0c;可以为理解顺序表提供更丰富的视角。&#xff08;不过最主要的区别在于顺序表上下卷中的顺…

Python | 计算位涡平流项

写在前面 最近忙着复习、考试…都没怎么空敲代码&#xff0c;还得再准备一周考试。。。等考完试再慢慢更新了&#xff0c;今天先来浅更一个简单但是使用的python code 在做动力机制分析时&#xff0c;我们常常需要借助收支方程来诊断不同过程的贡献&#xff0c;其中最常见的一…

51单片机-点亮LED灯

目录 新建项目选择型号添加新文件到该项目设置字体和utf-8编码二极管如何区分正负极原理&#xff1a;CPU通过寄存器来控制硬件电路 用P2寄存器的值控制第一个灯亮进制转换编译查看P2寄存器的地址生成HEX文件把代码下载到单片机中 新建项目 选择型号 stc是中国生产的、这个里面…

利用Linked SQL Server提权

点击星标&#xff0c;即时接收最新推文 本文选自《内网安全攻防&#xff1a;红队之路》 扫描二维码五折购书 利用Linked SQL Server提权 Linked SQL server是一个SQL Server数据库中的对象&#xff0c;它可以连接到另一个SQL Server或非SQL Server数据源&#xff08;如Oracle&a…

初学者轻松搞定19个经典的Python程序以及代码演示

Python的经典程序展示了Python语言基本特性和功能的简单示例,这些程序在学习和理解Python编程语言的过程中起着至关重要的作用. 一些常见的经典Python程序及其在学习Python时的功能&#xff1a; 1.Hello, World! print("Hello, World!")解释:这是Python的基本输出…

primeflex overflow样式类相关的用法和案例

文档地址&#xff1a;https://primeflex.org/overflow 案例1 <script setup> import axios from "axios"; import {ref} from "vue";const message ref("frontend variable") axios.get(http://127.0.0.1:8001/).then(function (respon…

【Flink】Flink SQL

一、Flink 架构 Flink 架构 | Apache Flink 二、设置TaskManager、Slot和Parallelism 在Apache Flink中&#xff0c;设置TaskManager、Slot和Parallelism是配置Flink集群性能和资源利用的关键步骤。以下是关于如何设置这些参数的详细指南&#xff1a; 1. TaskManager 设置 …

【漏洞复现】致远互联FE协作办公平台——SQL注入

声明&#xff1a;本文档或演示材料仅供教育和教学目的使用&#xff0c;任何个人或组织使用本文档中的信息进行非法活动&#xff0c;均与本文档的作者或发布者无关。 文章目录 漏洞描述漏洞复现测试工具 漏洞描述 致远互联FE协作办公平台是一个专注于协同管理软件领域的数智化运…

关于内存和外存文件不同字符集下占用空间大小问题

关于内存和外存不同字符集下文件占用空间大小问题 存储&#xff08;外存&#xff09;的文件中的字符&#xff1a; ASCII&#xff1a;每个字符占用1个字节&#xff0c;用来存储英文字符和常用标点符号。ISO-8859-1&#xff1a;每个字符占用1个字节&#xff0c;向下兼容ASCII。G…

DS18B20单总线数字温度传感器国产替代MY18E20 MY1820 MY18B20Z MY18B20L(一)

前言 DS18B20是全球第一个单总线数字温度传感器&#xff0c;推出时间已经超过30年&#xff0c;最早由美国达拉斯半导体公司推出&#xff0c;2001年1月&#xff0c;美信以25亿美元收购达拉斯半导体&#xff08;Dallas Semiconductor&#xff09;&#xff0c;而美信在2021年8月被…

DM达梦数据库存储过程

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; &#x1f49d;&#x1f49…

RDMA通信2:RDMA基本元素和组成 通信过程元素关系解析 视频教程

哈哈哈&#xff0c;今天我们把下面这张图理解了&#xff0c;我们的任务就完成了&#xff01; 视频教程在这&#xff1a;1.2 RDMA基本元素和组成 通信过程元素关系解析_哔哩哔哩_bilibili 一、WQ和WQE 工作队列元素(work queue element,WQE)&#xff1a;是软件下发给硬件的任务…

Apache Ranger 2.4.0 集成Hive 3.x(Kerbos)

一、解压tar包 tar zxvf ranger-2.4.0-hive-plugin.tar.gz 二、修改install.propertis POLICY_MGR_URLhttp://localhost:6080REPOSITORY_NAMEhive_repoCOMPONENT_INSTALL_DIR_NAME/BigData/run/hiveCUSTOM_USERhadoop 三、进行enable [roottv3-hadoop-01 ranger-2.4.0-hive…

什么是TOGAF架构框架的ADM方法?

ADM是架构开发方法&#xff08; Architecture Development Method&#xff09;&#xff0c;为开发企业架构所要执行的各个步骤以及它们质检的关系进行详细的定义&#xff0c;它是TOGAF规范中最为核心的内容。 ADM的具体步骤&#xff1a; 预备阶段&#xff08;Preliminary Phas…

STM32第十三课:DMA多通道采集光照烟雾

文章目录 需求一、DMA&#xff08;直接存储器存取&#xff09;二、实现流程1.时钟使能2.设置外设寄存器地址3.设置存储器地址4.设置要传输的数据量5.设置通道优先级6.设置传输方向7.使通道和ADC转换 三、数据处理四、需求实现总结 需求 通过DMA实现光照强度和烟雾浓度的多通道…

【SkiaSharp绘图13】SKCanvas方法详解(二)填充颜色、封装对象、高性能绘制、点(集)(多段)线、圆角矩形、Surface、沿路径绘制文字

文章目录 SKCanvas方法DrawColor 填充颜色DrawDrawable 绘制封装对象DrawImage 高性能绘制图像SKBitmap与SKImage对比DrawPicture 绘制图像SKPicture DrawPoint / DrawPoints 绘制点DrawRoundRect/DrawRoundRectDifference绘制圆角矩形DrawSurface 绘制SurfaceDrawTextOnPath沿…

List接口, ArrayList Vector LinkedList

Collection接口的子接口 子类Vector&#xff0c;ArrayList&#xff0c;LinkedList 1.元素的添加顺序和取出顺序一致&#xff0c;且可重复 2.每个元素都有其对应的顺序索引 方法 在index 1 的位置插入一个对象&#xff0c;list.add(1,list2)获取指定index位置的元素&#…