Spring源码二十:Bean实例化流程三

上一篇Spring源码十九:Bean实例化流程二中,我们主要讨论了单例Bean创建对象的主要方法getSingleton了解到了他的核心流程无非是:通过一个简单工厂的getObject方法来实例化bean,当然spring在实例化前后提供了扩展如:beforeSingletonCreation与afterSingletonCreate,同样为了提供性能会将实例化后的单例bean放入缓存中;又因为spring设计之初存在三级缓存,所以在放入缓存的时候又会将其他两次的缓存清除。

简单的回忆了之前的内容,我们发现还有一个很重要的点我们没有说到那就是怎么通过简单工厂来创建实例对象的,这一篇咱们详细讨论一下:


createBean

	/*** Central method of this class: creates a bean instance, 创建bean实例对象* populates the bean instance, applies post-processors, etc. 填充bean实例、应用后置处理器* @see #doCreateBean*/@Overrideprotected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {if (logger.isTraceEnabled()) {logger.trace("Creating instance of bean '" + beanName + "'");}RootBeanDefinition mbdToUse = mbd;// Make sure bean class is actually resolved at this point, and// clone the bean definition in case of a dynamically resolved Class// which cannot be stored in the shared merged bean definition.// 判断需要创建的bean是否可以实例化、是否可以通过当前类加载器加载Class<?> resolvedClass = resolveBeanClass(mbd, beanName);if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {mbdToUse = new RootBeanDefinition(mbd);mbdToUse.setBeanClass(resolvedClass);}// Prepare method overrides.// 准备bean中的方法覆盖try {mbdToUse.prepareMethodOverrides();}catch (BeanDefinitionValidationException ex) {throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),beanName, "Validation of method overrides failed", ex);}try {// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.// 给BeanPostProcessors一个返回代理而不是目标bean实例的机会。Object bean = resolveBeforeInstantiation(beanName, mbdToUse);// 如果bean配置类后置处理器PostProcessor,则这里返回一个proxy代理对象if (bean != null) {return bean;}}catch (Throwable ex) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,"BeanPostProcessor before instantiation of bean failed", ex);}try {// bean实例对象创建方法Object beanInstance = doCreateBean(beanName, mbdToUse, args);if (logger.isTraceEnabled()) {logger.trace("Finished creating instance of bean '" + beanName + "'");}return beanInstance;}catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {// A previously detected exception with proper bean creation context already,// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.throw ex;}catch (Throwable ex) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);}}

因为lockup-method属性与repliace-methon配置属性,现在基本上没有使用场景,而resolveBeanClass与preprareMethodOverrides是为了是实现这个两个方法而生的,所以我们直接来看 resolveBeforeInstantiation方法。

resolveBeforeInstantiation

@Nullableprotected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {Object bean = null;if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {// Make sure bean class is actually resolved at this point.if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {Class<?> targetType = determineTargetType(beanName, mbd);if (targetType != null) {// BeanPostProcessor前置处理方法bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);if (bean != null) {// BeanPostProcessor后置处理方法bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);}}}mbd.beforeInstantiationResolved = (bean != null);}return bean;}protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);if (result != null) {return result;}}}return null;}public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;for (BeanPostProcessor processor : getBeanPostProcessors()) {Object current = processor.postProcessAfterInitialization(result, beanName);if (current == null) {return result;}result = current;}return result;}

InstantiationAwareBeanPostProcessorBeanPostProcessor 的一个子接口,提供了以下方法,用于在 Bean 实例化的不同阶段进行干预:

  • postProcessBeforeInstantiation(Class<?> beanClass, String beanName): 在 Bean 实例化之前调用。
  • postProcessAfterInstantiation(Object bean, String beanName): 在 Bean 实例化之后调用。
  • postProcessProperties(PropertyValues pvs, Object bean, String beanName): 在 Bean 的属性设置之前调用。

这些方法提供了在 Bean 实例化过程中进行自定义逻辑处理的机会,可以用于 Bean 的替换、属性的预处理等操作。

示例代码:

public class CustomInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {@Overridepublic Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {if ("myBean".equals(beanName)) {System.out.println("Before instantiation of " + beanName);// 可以返回一个代理对象或自定义的 Bean 实例}return null; // 返回 null 表示继续默认的实例化过程}@Overridepublic boolean postProcessAfterInstantiation(Object bean, String beanName) {System.out.println("After instantiation of " + beanName);return true; // 返回 true 表示继续进行属性设置}@Overridepublic PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {System.out.println("Processing properties for " + beanName);return pvs; // 可以修改属性值}
}

InstantiationAwareBeanPostProcessor 扩展了 BeanPostProcessor 的功能,提供了在 Bean 实例化的不同阶段进行干预的能力。通过实现 InstantiationAwareBeanPostProcessor 接口,开发人员可以在 Bean 实例化过程中插入自定义逻辑,实现更灵活的 Bean 管理和控制。

实例化与初始化

为了更好地理解 BeanPostProcessorInstantiationAwareBeanPostProcessor 的区别,我们需要明确实例化和初始化的概念。

  • 实例化:实例化是从零到一创建一个 Bean 的过程,即通过调用构造函数生成 Bean 的实例。
  • 初始化:初始化是在 Bean 实例化之后进行的配置过程,包括属性注入、调用初始化方法等。

在 Spring 容器中,Bean 的生命周期大致分为以下几个阶段:

  1. 实例化:通过调用构造函数创建 Bean 实例。
  2. 属性注入:将依赖的属性注入到 Bean 中。
  3. 初始化:调用自定义的初始化方法,进行额外的配置。

BeanPostProcessor 与 InstantiationAwareBeanPostProcessor 的区别

  • 作用阶段

    • BeanPostProcessor 主要作用于初始化阶段,即在 Bean 的属性已经注入之后进行处理。
    • InstantiationAwareBeanPostProcessor 作用于实例化阶段和属性注入阶段,允许在 Bean 实例化之前、之后以及属性注入之前进行处理。
  • 用途

    • BeanPostProcessor 常用于在 Bean 初始化之前和之后执行一些通用的处理逻辑,如代理增强、配置验证等。
    • InstantiationAwareBeanPostProcessor 常用于在 Bean 实例化过程中执行一些特殊的处理逻辑,如提前终止 Bean 创建、动态生成代理对象、修改属性注入逻辑等。

这个方法是在 Bean 初始化后应用所有注册的 BeanPostProcessorpostProcessAfterInitialization 方法,其设计和实现反映了 Spring 框架中依赖注入和面向切面编程的核心理念。

Spring Bean 生命周期管理

在 Spring 框架中,Bean 的生命周期经历了多个阶段,包括实例化、依赖注入、初始化和销毁等。applyBeanPostProcessorsAfterInitialization 方法所处的阶段是在 Bean 初始化之后,即在所有属性被设置后,执行自定义的后处理逻辑。

BeanPostProcessor 接口作用

BeanPostProcessor 接口定义了在 Bean 初始化前后可以插入自定义逻辑的能力。Spring 容器在创建 Bean 的过程中,会检查是否注册了 BeanPostProcessor,如果有,则会在相应的阶段调用其方法。其中,postProcessAfterInitialization 方法是在 Bean 初始化完成后被调用的,允许开发者对 Bean 进行额外的处理或修改。

applyBeanPostProcessorsAfterInitialization 方法分析

  1. 初始化结果对象:方法开始时,首先将 result 对象初始化为 existingBean,即当前的 Bean 实例。这个 existingBean 是在容器中已经完成初始化的对象。

  2. 遍历处理器列表:方法接着遍历所有注册的 BeanPostProcessor,对每一个后处理器调用其 postProcessAfterInitialization 方法。

    • 每个处理器可以在方法内部执行任何与 Bean 相关的操作,例如添加代理、执行验证、修改属性等。
    • 如果某个处理器返回 null,则表示不需要进一步处理,直接返回当前的 result 对象。
  3. 返回处理后的结果:最终返回经过所有后处理器处理后的 result 对象。这个对象可能是原始的 existingBean,也可能是经过多个处理器处理后的新对象。

技术原理分析

  • 面向切面编程(AOP)的应用:通过 BeanPostProcessor 接口,Spring 实现了 AOP 的一种简单形式。开发者可以在 Bean 初始化后插入切面逻辑,例如添加事务、日志等。

  • 依赖注入的增强:允许在 Bean 初始化后对依赖关系进行增强或修改,以适应不同的运行时需求。

  • 灵活性与可扩展性:applyBeanPostProcessorsAfterInitialization 方法展示了 Spring 框架在管理 Bean 生命周期时的高度灵活性和可扩展性。开发者可以通过注册自定义的 BeanPostProcessor 实现特定的业务逻辑,而不必修改现有的 Bean 实现代码。

applyBeanPostProcessorsAfterInitialization 方法在 Spring 框架中扮演了重要角色,通过它,开发者可以在 Bean 初始化完成后添加自定义逻辑,扩展和定制应用程序的行为。理解这个方法的工作原理和技术实现,有助于深入理解 Spring 容器的工作机制,提升对 Bean 生命周期管理的控制和应用开发的灵活性。

总结

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

arp缓存中毒实验

文章目录 一、相关知识1.什么是arp&#xff08;地址解析协议&#xff09;2.什么是免费arp&#xff08;1&#xff09;简介&#xff08;2&#xff09;主要应用&#xff08;3&#xff09;代码 3.什么是arp缓存中毒&#xff08;1&#xff09;简介&#xff08;2&#xff09;过程&…

windows系统无法使用网络共享服务,设置防火墙入站规则解决

我们使用虚拟机的时候&#xff0c;已经配置好了网络&#xff0c;但是虚拟机和物理机就是无法通讯。可以使用关闭防火墙的方式解决这个问题&#xff0c;但是这个方法不是长久之计&#xff0c;非常不安全。那么&#xff0c;有什么其他的解决办法吗&#xff1f; 其中&#xff0c;p…

基于STM主题模型的主题提取分析-完整代码数据

直接看结果: 代码: import re from collections import defaultdict import random import matplotlib.pyplot as plt import numpy as npimport pandas as pd import numpy as np import re from sklearn.feature_extraction.text import CountVectorizer from nltk.corpus…

grafana数据展示

目录 一、安装步骤 二、如何添加喜欢的界面 三、自动添加注册客户端主机 一、安装步骤 启动成功后 可以查看端口3000是否启动 如果启动了就在浏览器输入IP地址&#xff1a;3000 账号密码默认是admin 然后点击 log in 第一次会让你修改密码 根据自定义密码然后就能登录到界面…

如何在 CentOS 上配置本地 YUM 源

引言 CentOS 作为一个流行的企业级 Linux 发行版&#xff0c;依赖 YUM&#xff08;Yellowdog Updater, Modified&#xff09;来管理软件包。YUM 源&#xff08;Repository&#xff09;是软件包存储和分发的中心&#xff0c;它们通常位于互联网上。然而&#xff0c;在某些情况下…

Python神经模型评估微分方程图算法

&#x1f3af;要点 &#x1f3af;神经网络映射关联图 | &#x1f3af;执行时间分析 | &#x1f3af;神经网络结构降维 | &#x1f3af;量化图结构边作用 | &#x1f3af;数学评估算法实现 &#x1f36a;语言内容分比 &#x1f347;Python随机梯度下降算法 随机梯度下降是梯度…

python采集阿里巴巴历年员工人数统计报告

数据为2012到2022财年阿里巴巴每年的全职员工数量。截止2022年3月31日&#xff0c;阿里巴巴共有全职员工254941人&#xff0c;比上年增长3479人。 数据来源于阿里巴巴20-F和F-1文件 按阿里巴巴财政年度进行统计&#xff0c;阿里巴巴财年结束日期为每年3月31日 为全职员工人数 阿…

博客标题:C++中的继承:构建面向对象的基石

目录 ​编辑 引言 继承的基本形式 示例1&#xff1a;基本继承 继承的类型 示例2&#xff1a;不同类型的继承 多重继承 示例3&#xff1a;多重继承 继承与多态性 示例4&#xff1a;继承与多态 结论 结尾 引言 在面向对象编程&#xff08;OOP&#xff09;中&#xff…

庞加莱猜想真的被证明了吗

一般认为&#xff0c;庞加莱猜想作出巨大贡献的&#xff0c;主要是瑟斯顿(Thurston)&#xff0c;他给出了几何化猜想&#xff0c;认为宇宙一定由八种基本拓扑形状构成。 第一&#xff0c;在之前&#xff0c;1961年斯梅尔宣称证明了五维和五维以上成立的结论。1981年弗里德曼宣称…

一文理解 Treelite,Treelite 为决策树集成模型的部署和推理提供了高效、灵活的解决方案

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 一、什么是 Treelite&#xff1f; Treelite 是一个专门用于将决策树集成模型高效部署到生产环境中的机器学习模型编译器&#xff0c;特别适合处理大批量数据的推理任务&#xff0c;能够显著提升推理性能…

192.168.1.1路由器管理系统使用教程

节选自&#xff1a;192.168.1.1路由器管理系统-厂商有哪些-如何使用-无法登录原因-苏州稳联 什么是 192.168.1.1 路由器管理系统&#xff1f; 192.168.1.1 是大多数家庭路由器的默认 IP 地址&#xff0c;用于访问路由器的管理控制台。通过这个管理系统&#xff0c;用户可以配…

Pearson 相关系数的可视化辅助判断和怎么用

Pearson 相关系数的可视化辅助判断和怎么用 flyfish Pearson 相关系数 是一种用于衡量两个连续型变量之间线性相关程度的统计量。其定义为两个变量协方差与标准差的乘积的比值。公式如下&#xff1a; r ∑ ( x i − x ˉ ) ( y i − y ˉ ) ∑ ( x i − x ˉ ) 2 ∑ ( y i −…

国际网课平台Udemy上的亚马逊云科技AWS免费高分课程和创建、维护EC2动手实践

亚马逊云科技(AWS)是全球云行业最&#x1f525;火的云平台&#xff0c;在全球经济形势不好的大背景下&#xff0c;通过网课学习亚马逊云科技AWS基础备考亚马逊云科技AWS证书&#xff0c;对于找工作或者无背景转行做AWS帮助巨大。欢迎大家关注小李哥&#xff0c;及时了解世界最前…

数据类型及数据块认知

西门子STEP7编程语言 梯形图(LAD) 功能块图(FBD) 语句表(STL) 其中梯形图和功能块图可以相互转换 CPU常用数据区 信号输入区 I 信号输出区 Q 程序中表现形式&#xff0c;IX.X/QX.X;IWX/QWX-访问的是CPU输出输入过程映像区 另一种形式IWX:P/QWX:P-访问的是信号端口地址&#xf…

红酒的秘密配方:如何调配出个性化的口感?

在红酒的世界里&#xff0c;每一滴都蕴藏着大自然的秘密和酿酒师的匠心。那些令人陶醉的口感、迷人的色泽和香气&#xff0c;都是经过精心调配和时光酝酿的结果。今天&#xff0c;就让我们一起揭开红酒调配的神秘面纱&#xff0c;探索如何调配出个性化的口感&#xff0c;感受雷…

推荐4款免费好用文本转语音工具

Edge文本转语音 Edge文本转语音功能主要通过Edge-TTS实现。Edge-TTS是由微软开发的文本转语音&#xff08;TTS&#xff09;Python库&#xff0c;利用微软Azure Cognitive Services的强大功能&#xff0c;能够将文本信息转换成流畅自然的语音输出。该库支持多种中文语音语色&…

Idea使用EasyApi插件自动生成接口文档到Yapi

1.安装EasyApi插件 2.配置Yapi 设置-》EasyApi Yapi的Server 配置为Yari项目的地址 tokens&#xff1a;项目名Yapi项目里面的token&#xff1a;例如&#xff1a;test-project0e6cfb3c22c884a0fce108fffe554a20ca12341e421d7201233143ee440af36b mytest-portal0e6cfb3c22c884a…

【Linux进阶】文件系统4——文件系统特性

1.磁盘组成与分区的复习 首先说明一下磁盘的物理组成&#xff0c;整块磁盘的组成主要有&#xff1a; 圆形的碟片&#xff08;主要记录数据的部分&#xff09;&#xff1b;机械手臂&#xff0c;与在机械手臂上的磁头&#xff08;可擦写碟片上的数据);主轴马达&#xff0c;可以…

从“+AI”到“AI+”,时代进入“Next Level”

“创新的速度比创新本身更重要。”埃隆马斯克曾这样说到。 近日&#xff0c;由马斯克所掌舵的特斯拉&#xff0c;在2024年世界人工智能大会上正式推出了第二代Optimus&#xff08;擎天柱&#xff09;人形机器人&#xff0c;距离第一代面世&#xff0c;仅过去9个月。 加速升级…

Java 操作 Redis客户端

目录 1.渐进式遍历 2.Java 操作 Redis 客户端 2.1 引入依赖 2.2 配置端口转发 2.3 连接Redis Server 3.基础操作 3.1 set 和 get 3.2 exists 和 del 3.3 keys 3.4 expire 和 ttl 3.5 type 4.字符串操作 4.1 mget 和 mset 4.2 append 4.3 getrange 和 setrange 4.4 incr 和 d…