当前位置: 首页 > news >正文

4.Spring Context 装载过程源码分析

Spring的ApplicationContext是Spring框架中的核心接口之一,它扩展了BeanFactory接口,提供了更多的高级特性,如事件发布、国际化支持、资源访问等。ApplicationContext的装载过程是Spring框架中非常重要的一个环节。以下是ApplicationContext装载过程的源码分析:

1. 创建ApplicationContext实例
装载过程的第一步是创建一个ApplicationContext的实例。这通常通过调用ClassPathXmlApplicationContext、FileSystemXmlApplicationContext或AnnotationConfigApplicationContext等具体实现类的构造函数来完成。

ApplicationContext context = new ClassPathXmlApplicationContext(“applicationContext.xml”);
2. 初始化BeanFactory
在ApplicationContext的实现类中,装载过程首先会初始化一个DefaultListableBeanFactory实例,这是BeanFactory的一个具体实现。

DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
3. 设置BeanFactory属性
接着,ApplicationContext会设置BeanFactory的一些属性,如类加载器、Bean表达式解析器等。

beanFactory.setBeanClassLoader(getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory));
4. 注册BeanPostProcessors
ApplicationContext会注册所有的BeanPostProcessor实现类。这些处理器会在Bean的初始化前后被调用。

beanFactory.addBeanPostProcessor(new MyBeanPostProcessor());
5. 装载Bean定义
根据ApplicationContext的具体实现,它会从不同的源装载Bean定义。例如,ClassPathXmlApplicationContext会从类路径下的XML文件中装载Bean定义。

loadBeanDefinitions(beanFactory);
6. 初始化MessageSource
如果需要,ApplicationContext会初始化一个MessageSource用于国际化。

initMessageSource();
7. 初始化应用事件多播器
ApplicationContext会初始化一个应用事件多播器,用于事件发布和监听。

initApplicationEventMulticaster();
8. 注册事件监听器
注册所有的事件监听器。

registerEventListeners();
9. 初始化其他基础设施
初始化其他Spring框架的基础设施,如ResourcePatternResolver等。

10. 调用BeanFactory的preInstantiateSingletons方法
这个方法会触发所有剩余的非懒加载的单例Bean的初始化。

beanFactory.preInstantiateSingletons();
11. 调用refresh()方法
最后,ApplicationContext会调用自身的refresh()方法来完成装载过程。这个方法会执行上述所有步骤,并确保容器完全初始化和就绪。

public void refresh() throws BeansException, IllegalStateException {
// …
}
refresh()方法是装载过程的核心,它协调了容器的初始化和Bean的创建。通过分析refresh()方法的源码,我们可以深入理解Spring容器是如何工作的。

请注意,上述步骤可能会根据不同的ApplicationContext实现类和配置有所变化。此外,Spring框架的版本更新也可能带来一些实现上的变化。上述分析基于Spring框架的一般装载过程。

BeanFactoryPostProcessor源码分析

BeanFactoryPostProcessor是Spring框架中的一个重要接口,它允许开发者在容器实例化和属性赋值完成后,初始化Bean之前,执行一些自定义逻辑。BeanFactoryPostProcessor接口定义了一个方法:

public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
源码分析
在Spring容器初始化过程中,BeanFactoryPostProcessor的逻辑主要在AbstractApplicationContext类中实现。以下是源码分析的关键点:

注册BeanFactoryPostProcessor: 在容器初始化时,所有的BeanFactoryPostProcessor实现类都会被注册到容器中。

调用postProcessBeanFactory: 在BeanFactory的标准初始化之后,容器会调用所有注册的BeanFactoryPostProcessor的postProcessBeanFactory方法。这个方法允许开发者查看和修改BeanFactory中的Bean定义。

修改Bean定义: 在postProcessBeanFactory方法中,开发者可以添加新的Bean定义、修改现有Bean定义、或者删除某些Bean定义。

应用顺序: BeanFactoryPostProcessor的实现类可以定义它们的应用顺序。如果需要,可以通过实现Ordered接口或使用@Order注解来指定顺序。

调用时机: BeanFactoryPostProcessor的调用发生在Bean的属性赋值之后,初始化之前。这意味着,此时Bean的属性已经设置完成,但Bean还没有被初始化。

异常处理: 如果在BeanFactoryPostProcessor的调用过程中抛出了异常,容器会捕捉这个异常,并传播出去。

与BeanPostProcessor的区别: BeanFactoryPostProcessor作用于BeanFactory,而BeanPostProcessor作用于具体的Bean。BeanFactoryPostProcessor可以在Bean初始化之前对BeanFactory进行修改,而BeanPostProcessor可以在Bean的初始化过程中插入自定义逻辑。

示例
下面是一个简单的BeanFactoryPostProcessor实现示例,它在BeanFactory初始化后打印所有Bean定义的名称:

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {String[] beanNames = beanFactory.getBeanDefinitionNames();System.out.println("Bean names after BeanFactoryPostProcessor: ");for (String beanName : beanNames) {System.out.println(beanName);}
}

}
通过实现BeanFactoryPostProcessor接口,开发者可以在Spring容器初始化Bean之前,对BeanFactory进行自定义操作,这为实现一些高级特性提供了可能,例如自动装配、Bean定义的动态修改等。

BeanDefinitionRegistryPostProcessor源码分析

BeanDefinitionRegistryPostProcessor 是 Spring 框架中的一个接口,它扩展了 BeanFactoryPostProcessor 接口。与 BeanFactoryPostProcessor 相比,BeanDefinitionRegistryPostProcessor 提供了对 BeanDefinitionRegistry 的访问,允许在 post-processing 阶段注册新的 BeanDefinition。这使得开发者可以在容器的 BeanDefinition 加载完成之后、实例化 Bean 之前,动态地添加或修改 BeanDefinition。

以下是 BeanDefinitionRegistryPostProcessor 接口的定义:

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {

/*** 在 BeanFactoryPostProcessor 的 postProcessBeanFactory 调用之后调用。* 允许在 BeanDefinitionRegistry 中注册更多的BeanDefinition。* @param registry BeanDefinitionRegistry 的实例* @throws org.springframework.beans.BeansException*/
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

}
源码分析
扩展 BeanFactoryPostProcessor:BeanDefinitionRegistryPostProcessor 接口继承自 BeanFactoryPostProcessor,因此它拥有 postProcessBeanFactory 方法的能力,并且可以访问 ConfigurableListableBeanFactory。

postProcessBeanDefinitionRegistry 方法:这是 BeanDefinitionRegistryPostProcessor 的核心方法,它允许开发者在 BeanDefinitionRegistry 中注册新的 BeanDefinition 或修改现有的 BeanDefinition。

调用时机:postProcessBeanDefinitionRegistry 方法在 postProcessBeanFactory 方法之后调用,确保开发者在注册新的 BeanDefinition 时,已有的 BeanDefinition 已经加载完成。

BeanDefinitionRegistry:BeanDefinitionRegistry 是一个接口,它定义了注册、移除和获取 BeanDefinition 的方法。postProcessBeanDefinitionRegistry 方法提供了对 BeanDefinitionRegistry 的访问,使得开发者可以操作 BeanDefinition。

BeanDefinition 的动态注册:开发者可以在 postProcessBeanDefinitionRegistry 方法中使用 BeanDefinitionRegistry 的 registerBeanDefinition 方法来注册新的 BeanDefinition。

BeanDefinition 的修改:除了注册新的 BeanDefinition,开发者还可以修改现有的 BeanDefinition,例如更改 Bean 的作用域、添加属性等。

异常处理:如果在 postProcessBeanDefinitionRegistry 方法中抛出异常,容器会捕捉这个异常并传播出去,这可能会中断 Bean 的创建过程。

示例
下面是一个简单的 BeanDefinitionRegistryPostProcessor 实现示例,它在 BeanDefinitionRegistry 中注册一个新的 BeanDefinition:

public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {// 可以在这里访问和修改 beanFactory
}@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {// 注册一个新的 BeanDefinitionRootBeanDefinition beanDefinition = new RootBeanDefinition(MyBean.class);registry.registerBeanDefinition("myBean", beanDefinition);
}

}
通过实现 BeanDefinitionRegistryPostProcessor 接口,开发者可以在 Spring 容器的 BeanDefinition 加载完成后,动态地注册或修改 BeanDefinition,这为实现一些复杂的配置和自定义行为提供了强大的支持。

相关文章:

4.Spring Context 装载过程源码分析

Spring的ApplicationContext是Spring框架中的核心接口之一,它扩展了BeanFactory接口,提供了更多的高级特性,如事件发布、国际化支持、资源访问等。ApplicationContext的装载过程是Spring框架中非常重要的一个环节。以下是ApplicationContext装…...

mysql之数据存储单元

简介 在MySQL中,单行数据存储单元的大小并不是固定的,它取决于多种因素,如表结构中使用的数据类型以及所使用的存储引擎。 但是我们可以提供一些关于MySQL中典型行数据存储单元大小的一般性指引: 存储引擎 InnoDB(默认存储引擎) InnoDB中单行数据存储单元的大小通常在8-16…...

未来20年人工智能将如何塑造社会

照片由Brian McGowan在Unsplash上拍摄 更多资讯,请访问 2img.ai “人工智能会成为我们的救星还是我们的末日?” 几十年来,这个问题一直困扰着哲学家、科学家和科幻爱好者。 当我们踏上技术革命的边缘时,是时候透过水晶球&#x…...

Maven的依赖传递、依赖管理、依赖作用域

在Maven项目中通常会引入大量依赖,但依赖管理不当,会造成版本混乱冲突或者目标包臃肿。因此,我们以SpringBoot为例,从三方面探索依赖的使用规则。 1、 依赖传递 依赖是会传递的,依赖的依赖也会连带引入。例如在项目中…...

ArcGIS定义1.5度带坐标系与投影转换

​ 点击下方全系列课程学习 点击学习—>ArcGIS全系列实战视频教程——9个单一课程组合系列直播回放 点击学习——>遥感影像综合处理4大遥感软件ArcGISENVIErdaseCognition 对于ArcGIS如何定义高斯克吕格3度带、6度带,我相信大部分人都是比较清楚的&#xff0…...

艺术与科技的精湛融合:探讨AI绘画与AI动画的交汇点

前言 艺术与科技的精湛融合:探讨AI绘画与AI动画的交汇点 在当代社会中,艺术和科技的结合呈现出了从来灭有的创新和可能性。随着人工智能技术的不断发展,AI绘画与AI动画的融合愈发引人瞩目。这一融合不仅给艺术家们带来了更多创作的可能&…...

【移动应用开发期末复习】第五/六章

系列文章 第一章——Android平台概述 第一章例题 第二章——Android开发环境 第二章例题 第三章 第三章例题 第四章 系列文章界面布局设计线性布局表格布局帧布局相对布局约束布局控制视图界面的其他方法代码控制视图界面数据存储与共享首选项信息数据文件SQLite数据库Content…...

excel FORMULA

在Excel中,FORMULA 实际上是一个拼写错误。您可能是指 FORMULA 的正确拼写 FORMULA(这在Excel中不是有效的函数或关键字),但更可能是您想要讨论的是FORMULA(公式)的创建或使用。 在Excel中,您可…...

【学习】开发板接口

工作用到机器的开发板 有如上三个接口 。最右是仿真器,中间是RS232串口,最左是电源线 仿真器 这个是仿真器 接入机器那端用的是SWD模式,另一端通过USB接电脑(这小肥手拍的怪好看)仿真口连接了四条线分别是 VCC&#…...

主干网络篇 | YOLOv5/v7 更换骨干网络之 EfficientNet | 卷积神经网络模型缩放的再思考

主干网络篇 | YOLOv5/v7 更换骨干网络之 EfficientNet | 卷积神经网络模型缩放的再思考 1. 简介 近年来,深度卷积神经网络(CNN)在图像识别、目标检测等领域取得了巨大进展。然而,随着模型复杂度的不断提升,模型训练和…...

如何测试Java应用的性能?

如何测试Java应用的性能? 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿! 在开发Java应用程序的过程中,性能测试是一个不可忽视的重要环…...

css 动画

当涉及到CSS动画时,有几种方式可以实现动画效果。以下是一些常见的CSS动画技术: 使用keyframes规则:keyframes规则允许你创建一个动画序列,定义动画的关键帧和属性值。例如,你可以创建一个旋转动画,让一个…...

# 设置 Linux 安全策略允许本地 IP 开通了访问权限

设置 Linux 安全策略允许本地 IP 开通了访问权限 在 Linux 中设置安全策略通常涉及使用 iptables 或者 firewalld( 在较新的 Red Hat/CentOS 版本中)。以下是使用 iptables 允许特定本地 IP 访问的例子: 1、先清除现有的规则(谨…...

C++初学者指南第一步---14.函数调用机制

C初学者指南第一步—14.函数调用机制 文章目录 C初学者指南第一步---14.函数调用机制1.记住:内存的结构2.函数调用是如何工作的3. 不要引用局部变量4. 常见编译器优化5. Inlining内联 1.记住:内存的结构 堆(自由存储) 用于动态存…...

Apache Flink类型及序列化研读生产应用|得物技术

一、背景 序列化是指将数据从内存中的对象序列化为字节流,以便在网络中传输或持久化存储。序列化在Apache Flink中非常重要,因为它涉及到数据传输和状态管理等关键部分。Apache Flink以其独特的方式来处理数据类型以及序列化,这种方式包括它…...

如何使用代理 IP 防止多个 Facebook 帐户关联 - 最佳实践

在社交媒体被广泛应用的今天,Facebook作为全球最大的社交网络平台之一,面临着很多挑战,其中之一就是用户行为的管理和安全。 为了防止多个账户之间的关联和滥用,Facebook需要采取一系列措施,其中包括使用静态住宅代理…...

DDei在线设计器-API-DDeiAbstractShape

DDeiAbstractShape DDeiAbstractShape代表是所有可见图形的父类,定义了图形所需要的公共属性和方法。   DDeiAbstractShape实例包含了一个图形的所有数据和渲染器,在获取后可以通过它访问其他内容。DDeiAbstractShape中的layer指向所在图层,stage指向所…...

IPython的使用技巧整理

关于IPython的使用技巧有很多,这里只是梳理了几个常用的以及我目前遇到过的,其他的技巧还没使用过,所以就没有列出来。 01|Tab键自动完成:在shell中输入表达式时,只要按下Tab键,当前命名空间中任何与已输入的字符串相…...

vue项目纯前端实现导出pdf文件

1、下载插件 npm install html2canvas npm install jspdf2、创建htmlToPdf.js,地址:src/utils/htmlToPdf.js import html2Canvas from html2Canvas import JsPDF from jspdf export default { install(Vue, options) { Vue.prototype.getPdfFromH…...

以Bert训练为例,测试torch不同的运行方式,并用torch.profile+HolisticTraceAnalysis分析性能瓶颈

以Bert训练为例,测试torch不同的运行方式,并用torch.profileHolisticTraceAnalysis分析性能瓶颈 1.参考链接:2.性能对比3.相关依赖或命令4.测试代码5.HolisticTraceAnalysis代码6.可视化A.优化前B.优化后 以Bert训练为例,测试torch不同的运行方式,并用torch.profileHolisticTra…...

XML Group端口详解

在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级

在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...

Android15默认授权浮窗权限

我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案

JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停​​ 1. ​​安全点(Safepoint)阻塞​​ ​​现象​​:JVM暂停但无GC日志,日志显示No GCs detected。​​原因​​:JVM等待所有线程进入安全点(如…...

AI书签管理工具开发全记录(十九):嵌入资源处理

1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...

基于matlab策略迭代和值迭代法的动态规划

经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...

以光量子为例,详解量子获取方式

光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...

【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题

【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found"​, "n…...

【JVM面试篇】高频八股汇总——类加载和类加载器

目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...

【LeetCode】3309. 连接二进制表示可形成的最大数值(递归|回溯|位运算)

LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 题目描述解题思路Java代码 题目描述 题目链接:LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 给你一个长度为 3 的整数数组 nums。 现以某种顺序 连接…...