请你谈谈:spring bean的生命周期 - 阶段2:Bean实例化阶段
在Spring框架中,Bean的实例化是Bean生命周期中的一个重要阶段。这个过程包括两个关键的子阶段:Bean实例化前阶段和Bean实例化阶段本身。
BeanFactoryPostProcessor:BeanFactoryPostProcessor是容器启动阶段Spring提供的一个扩展点,主要负责对注册到BeanDefinationRegistry中的一个个的BeanDefination进行一定程度上的修改与替换。例如使用占位符配置元信息,例如配置Jdbc的DataSource连接的时候可以这样配置:
<property name="driverClassName" value="${jdbc.driverClassName}"> </property>
BeanFactoryPostProcessor就会对注册到BeanDefinationRegistry中的BeanDefination做最后的修改,替换$占位符为配置文件中的真实的数据。至此,整个容器启动阶段就算完成了,容器的启动阶段的最终产物就是注册到BeanDefinationRegistry中的一个个BeanDefination了,这就是Spring为Bean实例化所做的预热的工作:

BeanFactoryPostProcessor 是 Spring 框架中的一个高级接口,允许在 Spring IoC 容器完全初始化之前(准确点说应该是:实例化之前),对 BeanFactory 中的 Bean 定义(BeanDefinition)进行修改。当 Spring 容器启动时,它会检测并调用所有实现了 BeanFactoryPostProcessor 接口的 bean,为开发者提供了在容器启动过程中定制和修改容器内部结构的机会。
BeanDefinitionRegistry 是 BeanFactory 的一个子接口,提供了动态注册 BeanDefinition 的能力。结合使用 BeanFactoryPostProcessor 和 BeanDefinitionRegistry,你可以动态地添加、修改或删除 Bean 定义。
下面是一个使用 BeanFactoryPostProcessor 和 BeanDefinitionRegistry 来替换或增强 Bean 定义的例子:
public interface UserService {void performAction();
}
public class OriginalUserService implements UserService {@Override public void performAction() { System.out.println("Original UserService performing action."); }
}
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.Configuration;public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;// 替换 OriginalUserService Bean BeanDefinition originalUserServiceDef = registry.getBeanDefinition("originalUserService");if (originalUserServiceDef != null) {BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(EnhancedUserService.class);builder.addConstructorArgReference("originalUserService"); // 注入原始的 UserService BeanAbstractBeanDefinition beanDefinition = builder.getBeanDefinition();registry.registerBeanDefinition("enhancedUserService", beanDefinition);}}// 模拟增强的 UserService 实现 static class EnhancedUserService implements UserService {private final OriginalUserService originalUserService;public EnhancedUserService(OriginalUserService originalUserService) {this.originalUserService = originalUserService;}@Overridepublic void performAction() {System.out.println("Before enhanced action...");originalUserService.performAction();System.out.println("After enhanced action...");}}
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class AppConfig {@Beanpublic UserService originalUserService() {return new OriginalUserService();}@Beanpublic CustomBeanFactoryPostProcessor userServiceBeanFactoryPostProcessor() {return new CustomBeanFactoryPostProcessor();}
}
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.ApplicationContext; public class Main { public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); UserService originalUserService = context.getBean("enhancedUserService", UserService.class);originalUserService.performAction(); }
}
输出如下所示:
Before enhanced action...
Original UserService performing action.
After enhanced action...
通过上述步骤,我们展示了如何在 Spring 容器中使用 BeanFactoryPostProcessor 和 BeanDefinitionRegistry 来动态地修改或增强 Bean 定义。这种方法特别适用于在不修改原始类代码的情况下,对应用进行扩展或修改。然而,在实际应用中,应谨慎使用这种方法,因为它可能会使应用的配置和依赖关系变得复杂和难以管理。
接下来解释加载方式的知识点:
选择懒加载的方式,那么直到我们伸手向Spring要依赖对象实例之前,其都是以BeanDefinationRegistry中的一个个的BeanDefination的形式存在,也就是Spring只有在我们需要依赖对象的时候才开启相应对象的实例化阶段;
而如果我们不是选择懒加载的方式,容器启动阶段完成之后,将立即启动Bean实例化阶段,通过隐式的调用所有依赖对象的getBean方法来实例化所有配置的Bean并保存起来。
1、对象创建策略:对象的创建采用了策略模式,BeanDefinationRegistry中的BeanDefination,我们可以使用反射的方式创建对象,也可以使用CGlib字节码生成创建对象。
2、BeanWrapper:由于Spring IOC容器为了统一对不同类型对象的访问,Spring给所有创建的Bean实例穿上了一层外套BeanWrapper。BeanWrapper实际上是对反射相关API的简单封装,我们要获取某个对象的属性、调用某个对象的方法,现在不需要在写繁杂的反射API了以及处理一堆麻烦的异常,直接通过BeanWrapper就可以完成相关操作。
在Spring框架中,BeanWrapper是一个非常重要的接口,它提供了对JavaBean属性的访问和修改的能力,同时也支持对JavaBean方法的调用。BeanWrapper是Spring IoC容器内部使用的核心组件之一,用于在Bean的实例化过程中设置Bean的属性值。以下是在Spring中BeanWrapper的用法:
1. 封装Bean实例
BeanWrapper是对JavaBean实例的封装,它允许Spring IoC容器以统一的方式访问和修改Bean的属性。当Spring IoC容器创建了一个Bean的实例后,它会使用BeanWrapper来封装这个实例,并通过BeanWrapper来设置Bean的属性值。
2. 访问和修改Bean属性
BeanWrapper提供了丰富的API来访问和修改Bean的属性。例如,可以使用getPropertyValue(String propertyName)方法来获取Bean的某个属性值,使用setPropertyValue(String propertyName, Object value)方法来设置Bean的某个属性值。此外,BeanWrapper还支持嵌套属性的访问和修改,例如可以通过"address.city"这样的属性名来访问和修改嵌套在address属性中的city属性。
3. 类型转换
在设置Bean属性值时,BeanWrapper会考虑属性值的类型转换。如果属性值的类型与Bean属性所需的类型不匹配,BeanWrapper会尝试使用注册在PropertyEditorRegistry中的属性编辑器(PropertyEditor)或ConversionService来进行类型转换。这使得开发者可以灵活地处理类型转换问题,而无需编写额外的代码。
4. 与Spring IoC容器的集成
BeanWrapper是Spring IoC容器内部使用的核心组件之一,它与Spring IoC容器的其他组件紧密集成。在Bean的实例化过程中,Spring IoC容器会创建BeanWrapper实例来封装Bean的实例,并通过BeanWrapper来设置Bean的属性值。此外,Spring IoC容器还利用BeanWrapper来支持依赖注入、AOP等功能。
5. 示例用法
虽然用户很少需要直接使用BeanWrapper进行编程,但了解其用法对于深入理解Spring IoC容器的内部机制非常有帮助。以下是一个简化的示例,展示了如何在Spring IoC容器外部使用BeanWrapper:
package com.springIoc.BeanDefinitionDemo;import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;public class SpringBeanWrapperExample {public static void main(String[] args) {// 创建一个JavaBean实例Person person = new Person();// 创建BeanWrapperImpl实例来包装Person对象BeanWrapper personWrapper = new BeanWrapperImpl(person);// 使用BeanWrapper设置属性值personWrapper.setPropertyValue("name", "John Doe");personWrapper.setPropertyValue("age", 30);// 获取BeanWrapper封装的Bean实例并调用其方法(如果需要的话)Person modifiedPerson = (Person) personWrapper.getWrappedInstance();modifiedPerson.greet(); // 假设Person类有一个greet()方法}// 假设的Person类,与前面的示例相同// ...
}class Person {private String name;private Integer age;public Person() {}public Person(String name, Integer age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public void greet() {System.out.println("name = " + name);System.out.println("age = " + age);}
}
需要注意的是,上述示例仅用于演示BeanWrapper的用法,而在实际开发中,BeanWrapper的使用通常是由Spring IoC容器自动完成的,用户无需手动创建和使用BeanWrapper实例。
结论
BeanWrapper是Spring框架中一个非常重要的接口,它提供了对JavaBean属性的访问和修改的能力,同时也支持类型转换和与Spring IoC容器的集成。虽然用户很少需要直接使用BeanWrapper进行编程,但了解其用法对于深入理解Spring IoC容器的内部机制非常有帮助。
相关文章:
请你谈谈:spring bean的生命周期 - 阶段2:Bean实例化阶段
在Spring框架中,Bean的实例化是Bean生命周期中的一个重要阶段。这个过程包括两个关键的子阶段:Bean实例化前阶段和Bean实例化阶段本身。 BeanFactoryPostProcessor:BeanFactoryPostProcessor是容器启动阶段Spring提供的一个扩展点࿰…...
【开发指南】HTML和JS编写多用户VR应用程序的框架
1.概述 Networked-Aframe 的工作原理是将实体及其组件同步到连接的用户。要连接到房间,您需要将networked-scene组件添加到a-scene元素。对于要同步的实体,请向其添加networked组件。默认情况下,position和rotation组件是同步的,…...
C语言第6天作业 7月17日
删除字符串中的空格字符 从终端输入一个字符串,要求删除字符串中的空格字符。提示:可以新建一个辅助数组 #include <stdio.h> #include <string.h> int main(int argc, const char *argv[]) {char str[100];char str1[100];gets(str);for(in…...
【BES2500x系列 -- RTX5操作系统】深入探索CMSIS-RTOS RTX -- 配置篇 -- flash的使用 --(八)
💌 所属专栏:【BES2500x系列】 😀 作 者:我是夜阑的狗🐶 🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询! Ὁ…...
vue视频、图片自动轮播并伴随进度条
废话不多说直接上代 多余没用的部分自己看着删除 <template><div class"showImg"><el-carousel ref"carousel" trigger"hover" :autoplay"false" class"dimControl" :height"${(currenInnerWith*0.37…...
Android Studio环境安装指南
一、安装前注意事项: 安装android studio之前,请先检查下操作系统中的用户名(C盘->用户或user)下是否含有中文,如果含有中文,请新建一个用户(必须全部英文),JDK的安装和配置也请重新安装和配…...
CentOS 7 初始化环境配置详细
推荐使用xshell远程连接,如链接不上 请查看 CentOS 7 网络配置 修改主机名 hostname hostnamectl set-hostname xxx bash 关闭 SElinux 重启之后生效 配置yum源(阿里) 先备份CentOS-Base.repo,然后再下载 mv /etc/yum.repos…...
数据结构(双向链表)
链表的分类 链表的结构⾮常多样,以下情况组合起来就有8种(2 x 2 x 2)链表结构: 虽然有这么多的链表的结构,但是我们实际中最常⽤还是两种结构:单链表和双向带头循环链表 1.⽆头单向⾮循环链表:…...
关于Kafka的17个问题
1.Kafka 的设计时什么样的呢? Kafka 将消息以 topic 为单位进行归纳 将向 Kafka topic 发布消息的程序成为 producers. 将预订 topics 并消费消息的程序成为 consumer. Kafka 以集群的方式运行,可以由一个或多个服务组成,每个服务叫做一个…...
Redis 散列
1. 数据结构 我们自底向上来描述redis散列涉及的数据结构。 首先是负责存储键值的结构,Java 中存储的结构叫 Entry,redis里也差不多,叫dictEntry: typedef struct dictEntry {void *key; // 键,它是一个指针类型…...
ip地址错误无法上网怎么修复
在数字化日益普及的今天,网络已经成为我们生活中不可或缺的一部分。然而,当遇到IP地址错误导致无法上网的问题时,很多人可能会感到手足无措。那么,IP地址错误无法上网怎么修复?下面跟着虎观代理小二一起来了解一下吧。…...
数据库管理的艺术(MySQL):DDL、DML、DQL、DCL及TPL的实战应用(上:数据定义与控制)
文章目录 DDL数据定义语言1、创建数据库2、创建表3、修改表结构4、删除5、数据类型 列的约束主键约束(primary key)唯一约束(unique key)非空约束检查约束(check)外键约束(foreign keyÿ…...
成为CMake砖家(5): VSCode CMake Tools 插件基本使用
大家好,我是白鱼。 之前提到过,白鱼的主力 编辑器/IDE 是 VSCode, 也提到过使用 CMake Language Support 搭配 dotnet 执行 CMakeLists.txt 语法高亮。 对于阅读 CMakeLists.txt 脚本, 这足够了。 而在 C/C 开发过程中ÿ…...
【简洁明了】调节大模型的prompt的方法【带案例】
简明调节大模型的prompt的方法【简洁明了带案例】 1. 明确任务目标2. 提供上下文3. 指定格式4. 限制输出长度5. 使用示例6. 逐步引导7. 提供反面例子8. 使用CoT思维链9. 反复试验和调整方法九解释:乔哈里窗检视 最后 因为网上给出的调节prompt都 过于详细ÿ…...
【操作系统】文件管理——文件存储空间管理(个人笔记)
学习日期:2024.7.17 内容摘要:文件存储空间管理、文件的基本操作 在上一章中,我们学习了文件物理结构的管理,重点学习了操作系统是如何实现逻辑结构到物理结构的映射,这显然是针对已经存储了文件的磁盘块的࿰…...
微软GraphRAG +本地模型+Gradio 简单测试笔记
安装 pip install graphragmkdir -p ./ragtest/input#将文档拷贝至 ./ragtest/input/ 下python -m graphrag.index --init --root ./ragtest修改settings.yaml encoding_model: cl100k_base skip_workflows: [] llm:api_key: ${GRAPHRAG_API_KEY}type: openai_chat # or azu…...
数学建模-Topsis(优劣解距离法)
介绍 TOPSIS法(Technique for Order Preference by Similarity to Ideal Solution) 可翻译为逼近理想解排序法,国内常简称为优劣解距离法 TOPSIS 法是一种常用的综合评价方法,其能充分利用原始数据的信息, 其结果能精…...
嵌入式linux相机 转换模块
convert_manager.c #include <config.h> #include <convert_manager.h> #include <string.h>static PT_VideoConvert g_ptVideoConvertHead NULL;/*********************************************************************** 函数名称: Register…...
【自学安全防御】二、防火墙NAT智能选路综合实验
任务要求: (衔接上一个实验所以从第七点开始,但与上一个实验关系不大) 7,办公区设备可以通过电信链路和移动链路上网(多对多的NAT,并且需要保留一个公网IP不能用来转换) 8,分公司设备可以通过总…...
【Android】传给后端的Url地址被转码问题处理
一、问题 为什么使用Gson().toJson的时候,字符串中的会被转成\u003d 在 Gson 中,默认情况下会对某些特殊字符进行 HTML 转义,以确保生成的 JSON 字符串在 HTML 中是安全的。因此,字符 会被转义为 \u003d。你可以通过禁用 HTML 转…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...
Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...
C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
腾讯云V3签名
想要接入腾讯云的Api,必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口,但总是卡在签名这一步,最后放弃选择SDK,这次终于自己代码实现。 可能腾讯云翻新了接口文档,现在阅读起来,清晰了很多&…...
