Spring中Bean的生命周期
1.生命周期
Spring应用中容器管理了我们每一个bean的生命周期,为了保证系统的可扩展性,同时为用户提供自定义的能力,Spring提供了大量的扩展点。完整的Spring生命周期如下图所示,绿色背景的节点是ApplictionContext生命周期特有的节点,单纯从生命周期上来看,BeanFactory的生命周期和ApplicationContext的生命周期差异不大,不单独论述。
ApplicationContext和BeanFactory还有一个值得一提的差异是,ApplicationContext会自动查找容器内的BeanFactoryPostProcessor、InstantiationAwareBeanPostProcessor、BeanPostProcessor自动引用到上下文中;BeanFactory必须自己手动调用addBeanPostProcessor。
我把整个Bean的生命周期分为5个阶段,如图最左侧的大括号所示,分别是: 配置解析、实例化、依赖注入、初始化、销毁。下面我们会依次查看,它能做什么,Spring什么特性依赖于它,以及我们的开发中能怎么利用这个特性。
2. 配置解析

正常生命周期中,我们不直接参与配置解析,通过BeanFactoryPostProcessor的postProcessBeanFactory回调,我们能拿到ConfigurableListableBeanFactory,通过beanFactory.getBeanDefinition(beanName)对BeanDefinition对象做读取和设置。在Spring内部有两种使用场景
1. 做准备工作
在Bean实例化前,做准备工作。这类对象以CustomAutowireConfigurer、CustomEditorConfigurer为代表,CustomAutowireConfigurer继承BeanFactoryPostProcessor类,覆写postProcessBeanFactory,会从当前的BeanFactory中查找QualifierAnnotationAutowireCandidateResolver实例,并将customQualifierTypes里的注解类添加到QualifierAnnotationAutowireCandidateResolver中。
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {if (this.customQualifierTypes != null) {...DefaultListableBeanFactory dlbf = (DefaultListableBeanFactory)beanFactory;...QualifierAnnotationAutowireCandidateResolver resolver = (QualifierAnnotationAutowireCandidateResolver)dlbf.getAutowireCandidateResolver();Iterator var4 = this.customQualifierTypes.iterator();while(var4.hasNext()) {...resolver.addQualifierType(customType);}}
}
2. 改Bean定义
在实例化前,修改BeanDefinition中的配置中,比如替换占位符。这类对象以PropertyPlaceholderConfigurer为代表,PropertyPlaceholderConfigurer间接继承了BeanFactoryPostProcessor,核心逻辑都在doProcessProperties中,这里的BeanDefinitionVisitor的作用就是使用valueResolver将BeanDefinition中的占位符替换为配置文件中的值。
protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess, StringValueResolver valueResolver) {BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);...for(int var7 = 0; var7 < var6; ++var7) {...if (!curName.equals(this.beanName) || !beanFactoryToProcess.equals(this.beanFactory)) {BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(curName);...visitor.visitBeanDefinition(bd);}}...
}
看代码得到的额外收获是BeanDefinitionVisitor的使用,是典型的Visitor模式,当数据结构稳定,而操作不稳定时,用Visitor模式,能隔易变的逻辑独立在稳定的数据结构之外。
3. 实例化

3.1 postProcessBeforeInstantiation
这里将InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation做为实例化的一部分,因为postProcessBeforeInstantiation返回非null的情况下,将会跳过构造函数实例化,直接用postProcessBeforeInstantiation返回的对象做为bean实例。比如下面的例子,通过BeanFactory.getBean("globalProduct")返回的就是我们创建的id=5678的Product对象,并且跳过InstantiationAwareBeanPostProcessor的后两个回调函数。
public class ProductInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {if ("globalProduct".equals(beanName)) {System.out.println("postProcessBeforeInstantiation----->beanClass: " + beanClass.getName() + ",beanName: " + beanName);Product product = new Product();product.setId(5678L);product.setStaticScore(2.333F);product.setRelationScore(3.444F);product.setCategoryId(8765);return product;}return null;}...
}
3.2 构造函数
这里的构造函数实例化,不仅限于实际Java类的构造函数,还可以是FactoryBean.getObject,或者使用Spring的factory-bean、factory-method创建Bean的过程。
4. 依赖注入

4.1 InstantiationAwareBeanPostProcessor
通过InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation修改bean对象,完成属性注入。
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {if ("globalProduct".equals(beanName)) {System.out.println("postProcessAfterInstantiation----->bean: " + bean + ",beanName: " + beanName);PropertyDescriptor prop = BeanUtils.getPropertyDescriptor(bean.getClass(),"id");Method writer = prop.getWriteMethod();writer.invoke(bean,Long.valueOf(2222)); // 将globaleProduct bean的id改为2222}return true;
}
此外通过postProcessProperties回调,直接修改现有的PropertyValues或者往PropertyValues里新增PropertyValue即可
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {if ("globalProduct".equals(beanName)) {System.out.println("postProcessProperties----->pvs: " + pvs + ",bean: " + bean + ",beanName: " + beanName);MutablePropertyValues mpvs = (MutablePropertyValues) pvs;mpvs.addPropertyValue("id",3333); // 将globaleProduct bean的id改为3333return mpvs;}return pvs;
}
4.2 依赖注入
普通的setter方法注入、@Autowired基于方法入参、字段的注入。
4.3 回调接口
包括BeanNameAware、BeanFactoryAware、ApplicationContextAware,这3个接口都逻辑都很简单,提供一个set方法,容器将对于的对象通过set方法入参传递给bean实例。
private String beanName;
@Override
public void setBeanName(String name) {this.beanName = name;
}private BeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {this.beanFactory = beanFactory;
}private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;
}
5.初始化

5.1 BeanPostProcessor
BeanPostProcessor有两个方法,postProcessBeforeInitialization在Bean调用InitializingBean、init-method等初始化方法前调用
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if ("globalProduct".equals(beanName)) {System.out.println("postProcessBeforeInitialization>>> bean:" + bean);}return bean;
}
在Bean调用InitializingBean、init-method等初始化方法后调用
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if ("globalProduct".equals(beanName)) {System.out.println("postProcessAfterInitialization>>> bean:" + bean);}return bean;
}
5.2 InitializingBean
需要Bean对象自己实现InitializingBean接口的afterPropertiesSet方法,这里我们只是简单的打印。
public class Product implements InitializingBean {@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("Product.afterPropertiesSet");}
}
5.3 init-method、@PostConstruct
init-method和@PostConstruct作用和InitializingBean的afterPropertiesSet方法相同,用于做初始化动作。好处是我们的Bean不再需要继续一个Spring接口,而是通过配置或注解触发初始化方法调用。
@Bean(initMethod = "afterPropertiesSet")
public Product globalProduct() {Product product = new Product();...return product;
}
@PostConstruct
public void afterPropertiesSet() throws Exception {System.out.println("Product.afterPropertiesSet");
}
6. 销毁

6.1 DisposableBean
需要Bean对象实现DisposableBean的destroy方法,这里我们只是简单的打印
public class Product implements DisposableBean{public void destroy() throws Exception {System.out.println("Product.destroy");}
}
6.2 destroy-method、@PreDestroy
destroy-method和@PreDestroy的作用和DisposableBean的destroy方法作用一致,好处是不需要Bean实现Spring的接口。
@Bean(destroyMethod = "destroy")
public Product globalProduct() {Product product = new Product();...return product;
}
@PreDestroy
public void destroy() throws Exception {System.out.println("Product.destroy");
}
相关文章:
Spring中Bean的生命周期
1.生命周期 Spring应用中容器管理了我们每一个bean的生命周期,为了保证系统的可扩展性,同时为用户提供自定义的能力,Spring提供了大量的扩展点。完整的Spring生命周期如下图所示,绿色背景的节点是ApplictionContext生命周期特有的…...
IndexOutOfBoundsException: Index: 2048, Size: 2048] Controller接收对象集合长度超过2048错误
完整异常信息: org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [spring] in context with path [/jsgc] threw exception [Request processing failed; nested exception is org.springframework.beans.InvalidPropertyExce…...
2023年中国消费金融行业研究报告
第一章 行业概况 1.1 定义 中国消费金融行业,作为国家金融体系的重要组成部分,旨在为消费者提供多样化的金融产品和服务,以满足其消费需求。这一行业包括银行、消费金融公司、小额贷款公司等多种金融机构,涵盖了包括消费贷款在内…...
深度学习:什么是知识蒸馏(Knowledge Distillation)
1 概况 1.1 定义 知识蒸馏(Knowledge Distillation)是一种深度学习技术,旨在将一个复杂模型(通常称为“教师模型”)的知识转移到一个更简单、更小的模型(称为“学生模型”)中。这一技术由Hint…...
【Go】protobuf介绍及安装
目录 一、Protobuf介绍 1.Protobuf用来做什么 2. Protobuf的序列化与反序列化 3. Protobuf的优点和缺点 4. RPC介绍 <1>文档规范 <2>消息编码 <3>传输协议 <4>传输性能 <5>传输形式 <6>浏览器的支持度 <7>消息的可读性和…...
c语言编程题经典100例——(41~45例)
1,实现动态内存分配。 在C语言中,动态内存分配使用malloc、calloc、realloc和free函数。以下是一个示例: #include <stdio.h> #include <stdlib.h> int main() { int *ptr NULL; // 初始化为空 int n 5; // 假设我们想要分配5个整数…...
计算机毕业设计|基于SpringBoot+MyBatis框架健身房管理系统的设计与实现
计算机毕业设计|基于SpringBootMyBatis框架的健身房管理系统的设计与实现 摘 要:本文基于Spring Boot和MyBatis框架,设计并实现了一款综合功能强大的健身房管理系统。该系统涵盖了会员卡查询、会员管理、员工管理、器材管理以及课程管理等核心功能,并且…...
java学习part27线程死锁
基本就是操作系统的内容 138-多线程-线程安全的懒汉式_死锁_ReentrantLock的使用_哔哩哔哩_bilibili...
(二)Tiki-taka算法(TTA)求解无人机三维路径规划研究(MATLAB)
一、无人机模型简介: 单个无人机三维路径规划问题及其建模_IT猿手的博客-CSDN博客 参考文献: [1]胡观凯,钟建华,李永正,黎万洪.基于IPSO-GA算法的无人机三维路径规划[J].现代电子技术,2023,46(07):115-120 二、Tiki-taka算法(TTA…...
区间预测 | Matlab实现BP-KDE的BP神经网络结合核密度估计多变量时序区间预测
区间预测 | Matlab实现BP-KDE的BP神经网络结合核密度估计多变量时序区间预测 目录 区间预测 | Matlab实现BP-KDE的BP神经网络结合核密度估计多变量时序区间预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.BP-KDE多变量时间序列区间预测,基于BP神经网络多…...
LD_PRELOAD劫持、ngixn临时文件、无需临时文件rce
LD_PRELOAD劫持 <1> LD_PRELOAD简介 LD_PRELOAD 是linux下的一个环境变量。用于动态链接库的加载,在动态链接库的过程中他的优先级是最高的。类似于 .user.ini 中的 auto_prepend_file,那么我们就可以在自己定义的动态链接库中装入恶意函数。 也…...
循环神经网络训练情感分析
文章目录 1 循环神经网络训练情感分析2 完整代码3 代码详解 1 循环神经网络训练情感分析 下面介绍如何使用长短记忆模型(LSTM)处理情感分类LSTM模型是循环神经网络的一种,按照时间顺序,把信息进行有效的整合,有的信息…...
如何绕过某讯手游保护系统并从内存中获取Unity3D引擎的Dll文件
某讯的手游保护系统用的都是一套,在其官宣的手游加固功能中有一项宣传是对比较热门的Unity3d引擎的手游保护方案,其中对Dll文件的保护介绍如下, “Dll加固混淆针对Unity游戏,对Dll模块的变量名、函数名、类名进行加密混淆处理&…...
【C/C++笔试练习】公有派生、构造函数内不执行多态、抽象类和纯虚函数、多态中的缺省值、虚函数的描述、纯虚函数的声明、查找输入整数二进制中1的个数、手套
文章目录 C/C笔试练习选择部分(1)公有派生(2)构造函数内不执行多态(3)抽象类和纯虚函数(4)多态中的缺省值(5)程序分析(6)重载和隐藏&a…...
Linux shell中的函数定义、传参和调用
Linux shell中的函数定义、传参和调用: 函数定义语法: [ function ] functionName [()] { } 示例: #!/bin/bash# get limit if [ $# -eq 1 ] && [ $1 -gt 0 ]; thenlimit$1echo -e "\nINFO: input limit is $limit" e…...
YoloV8改进策略:基于RevCol,可逆的柱状神经网络的完美迁移,YoloV8的上分利器
文章目录 摘要论文:《RevCol:可逆的柱状神经网络》1、简介2、方法2.1、Multi-LeVEl ReVERsible Unit2.2、可逆列架构2.2.1、MACRo设计2.2.2、MicRo 设计2.3、中间监督3、实验部分3.1、图像分类3.2、目标检测3.3、语义分割3.4、与SOTA基础模型的系统级比较3.5、更多分析实验&l…...
九章量子计算机:引领量子计算的新篇章
九章量子计算机:引领量子计算的新篇章 一、引言 随着科技的飞速发展,量子计算已成为全球科研领域的前沿议题。九章量子计算机作为中国自主研发的量子计算机,具有划时代的意义。本文将深入探讨九章量子计算机的原理、技术特点、应用前景等方面,带领读者领略量子计算的魅力…...
什么是vue的计算属性
Vue的计算属性是一种特殊的属性,它的值是通过对其他属性进行计算得到的。计算属性可以方便地对模型中的数据进行处理和转换,同时还具有缓存机制,只有在依赖的数据发生变化时才会重新计算值。这使得计算属性更加高效,并且可以减少重…...
Linux中文件的打包压缩、解压,下载到本地——zip,tar指令等
目录 1 .zip后缀名: 1.1 zip指令 1.2 unzip指令 2 .tar后缀名 3. sz 指令 4. rz 指令 5. scp指令 1 .zip后缀名: 1.1 zip指令 语法:zip [namefile.zip] [namefile]... 功能:将目录或者文件压缩成zip格式 常用选项:…...
C语言——深入理解指针(4)
目录 1.回调函数 2. qsort 函数的使用 2.1 排序整型数据 2.2 排序结构体数据 3. qsort 函数的模拟实现 1.回调函数 回调函数就是通过一个函数指针调用的函数。 你把函数的地址作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,被调…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...
Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
【Java学习笔记】BigInteger 和 BigDecimal 类
BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点:传参类型必须是类对象 一、BigInteger 1. 作用:适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...
iview框架主题色的应用
1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题,无需引入,直接可…...
上位机开发过程中的设计模式体会(1):工厂方法模式、单例模式和生成器模式
简介 在我的 QT/C 开发工作中,合理运用设计模式极大地提高了代码的可维护性和可扩展性。本文将分享我在实际项目中应用的三种创造型模式:工厂方法模式、单例模式和生成器模式。 1. 工厂模式 (Factory Pattern) 应用场景 在我的 QT 项目中曾经有一个需…...

