专题四: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…

【本地调试】使用 Nginx 和 Hosts 文件实现本地开发调试请求转发

可以按照以下 nginx 配置来设置&#xff0c;通过 nginx 和 host 将网页的请求转发到本地的后端服务器&#xff0c;以方便本地开发调试 一、nginx 配置 worker_processes 1;events {worker_connections 1024; }http {include mime.types;default_type application/js…

【Python】 数据分析中的常见统计量:中位数

那年夏天我和你躲在 这一大片宁静的海 直到后来我们都还在 对这个世界充满期待 今年冬天你已经不在 我的心空出了一块 很高兴遇见你 让我终究明白 回忆比真实精彩 &#x1f3b5; 王心凌《那年夏天宁静的海》 中位数&#xff08;Median&#xff09;是统计学…

深入浅出3D感知中的优化与基于学习的技术1(原创系列)

近期几乎看了所有有关NERF技术论文&#xff0c;本身我研究的领域不在深度学习技术方向&#xff0c;是传统的机器人控制和感知。所以总结了下这部分基于学习的感知技术&#xff0c;会写一个新的系列教程讲解这部分三维感知技术的发展到最新的技术细节&#xff0c;并支持自己最近…

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

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

解析Java中1000个常用类:Currency类,你学会了吗?

在线工具站 推荐一个程序员在线工具站:程序员常用工具(http://cxytools.com),有时间戳、JSON格式化、文本对比、HASH生成、UUID生成等常用工具,效率加倍嘎嘎好用。程序员资料站 推荐一个程序员编程资料站:程序员的成长之路(http://cxyroad.com),收录了一些列的技术教程…

解析connectionReset异常的原因与解决方案

解析connectionReset异常的原因与解决方案 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们将深入探讨Java中connectionReset异常的原因及其解决方案。这…

遥远星辰中的觉醒:超大质量黑洞的苏醒与人类的未来

遥远星辰中的觉醒&#xff1a;超大质量黑洞的苏醒与人类的未来 在浩渺无垠的宇宙中&#xff0c;星辰的闪烁仿佛是时间的涟漪&#xff0c;穿越亿万年的距离&#xff0c;抵达我们的眼眸。而在这片星辰大海的深处&#xff0c;一个惊人的现象正在悄然上演——距离地球3.6亿光年之遥…

Unity获取剪切板内容粘贴板图片文件文字

最近做了一个发送消息的unity项目&#xff0c;需要访问剪切板里面的图片文字文件等&#xff0c;翻遍了网上的东西&#xff0c;看了不是需要导入System.Windows.Forms&#xff08;关键导入了unity还不好用&#xff0c;只能用在纯c#项目中&#xff09;&#xff0c;所以我看了下py…

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

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

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

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

机器人关节 viscous friction与结构阻尼

Viscous Friction&#xff08;粘性摩擦&#xff09; 定义&#xff1a;Viscous friction&#xff0c;也被称为粘性摩擦或粘滞摩擦&#xff0c;是机器人关节在运动过程中由于接触面之间的相互作用而产生的摩擦力。这种摩擦力与关节的运动速度有关&#xff0c;通常表现为速度越大&…

HarmonyOS开发实战:分布式文件系统-hmdfs

分布式文件系统提供跨设备的文件访问能力&#xff0c;适用于如下场景&#xff1a; 两台设备组网&#xff0c;A 设备可以无感读取和修改 B 设备的文件。 边缘服务器可以自动同步组网中多个嵌入式设备中的文件数据。 hmdfs 在分布式软总线动态组网的基础上&#xff0c;为网络上…

Ubuntu添加系统字体

&#xff08;2024.6.30&#xff09; 系统字体保存路径在/usr/share/fonts下&#xff0c;如果此目录下缺少字体&#xff0c;则使用其他可视化api&#xff08;如Python的pygame库&#xff09;的默认配置时可能会出现乱码问题。 往Ubuntu中添加字体的方法 方法一&#xff1a;手…

Ant Design Vue:如何提升你的前端开发效率?

目录 1. Ant Design Vue 简介 1.1 特性概览 1.2 安装与配置 2. 常用组件及使用示例 2.1 Button 按钮 2.2 Form 表单 2.3 Table 表格 2.4 Modal 对话框 3. 常见问题及解决方案 3.1 组件无法渲染 问题描述 解决方案 3.2 表单验证失效 问题描述 解决方案 3.3 表格…

Python | 计算位涡平流项

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

51单片机-点亮LED灯

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

token登录比密码登录有什么优势吗

token登录比密码登录有什么优势吗 使用令牌&#xff08;Token&#xff09;登录相比于密码登录具有一些优势&#xff0c;包括&#xff1a; 安全性&#xff1a;令牌通常采用加密技术&#xff0c;使得它们更难以被盗取或猜测。相比之下&#xff0c;密码存在被猜测、破解或被暴力攻…

解决浏览器兼容性问题的方法

解决浏览器兼容性问题的方法 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们来探讨如何解决网页开发中常见的浏览器兼容性问题。随着互联网技术的发展&…

java中输入输出流的继承关系

在 Java 中,输入输出流的继承关系主要围绕两个抽象基类展开:字节流基类 InputStream 和 OutputStream,以及字符流基类 Reader 和 Writer。这些类形成了 Java I/O 系统的基础,提供了丰富的子类以适应不同的输入输出需求。 字节流 字节流用于处理原始的二进制数据。 Input…