Spring Bean的生命周期与作用域详解

一、Spring Bean的生命周期

Spring Bean的生命周期指的是Bean从创建到销毁的整个过程。理解这个生命周期对于正确使用Spring框架至关重要,它可以帮助我们在适当的时机执行自定义逻辑。

1. 完整的Bean生命周期阶段

Spring Bean的生命周期可以分为以下几个主要阶段:

  1. 实例化(Instantiation):容器通过构造函数或工厂方法创建Bean实例

  2. 属性填充(Populate properties):设置Bean的属性值和依赖

  3. BeanNameAware.setBeanName():如果实现了BeanNameAware接口

  4. BeanFactoryAware.setBeanFactory():如果实现了BeanFactoryAware接口

  5. ApplicationContextAware.setApplicationContext():如果实现了ApplicationContextAware接口

  6. BeanPostProcessor.postProcessBeforeInitialization():BeanPostProcessor的前置处理

  7. @PostConstruct注解的方法:执行初始化回调

  8. InitializingBean.afterPropertiesSet():如果实现了InitializingBean接口

  9. 自定义init-method:执行配置的初始化方法

  10. BeanPostProcessor.postProcessAfterInitialization():BeanPostProcessor的后置处理

  11. Bean就绪可用:此时Bean可以被正常使用

  12. @PreDestroy注解的方法:容器关闭时执行销毁回调

  13. DisposableBean.destroy():如果实现了DisposableBean接口

  14. 自定义destroy-method:执行配置的销毁方法

2. 生命周期示例代码

public class ExampleBean implements BeanNameAware, InitializingBean, DisposableBean {private String name;public ExampleBean() {System.out.println("1. 实例化Bean");}public void setName(String name) {System.out.println("2. 设置属性值");this.name = name;}@Overridepublic void setBeanName(String name) {System.out.println("3. BeanNameAware.setBeanName()");}@PostConstructpublic void postConstruct() {System.out.println("5. @PostConstruct方法");}@Overridepublic void afterPropertiesSet() {System.out.println("6. InitializingBean.afterPropertiesSet()");}public void customInit() {System.out.println("7. 自定义init-method");}@PreDestroypublic void preDestroy() {System.out.println("9. @PreDestroy方法");}@Overridepublic void destroy() {System.out.println("10. DisposableBean.destroy()");}public void customDestroy() {System.out.println("11. 自定义destroy-method");}
}// 配置类
@Configuration
public class AppConfig {@Bean(initMethod = "customInit", destroyMethod = "customDestroy")public ExampleBean exampleBean() {ExampleBean bean = new ExampleBean();bean.setName("示例Bean");return bean;}
}

3. 生命周期流程图

实例化Bean → 设置属性 → Aware接口回调 → BeanPostProcessor前置处理 → 
@PostConstruct → afterPropertiesSet → init-method → 
BeanPostProcessor后置处理 → Bean就绪可用 → 
@PreDestroy → destroy() → destroy-method

二、Spring Bean的作用域

Spring框架支持多种Bean作用域,允许开发者根据需求控制Bean的创建方式和生命周期。

1. 标准作用域

Spring提供了以下标准作用域:

  1. singleton(单例,默认)

    • 每个Spring IoC容器中一个Bean定义对应一个实例

    • 所有对该Bean的请求都返回同一个实例

    • 生命周期与容器相同

  2. prototype(原型)

    • 每次请求都创建一个新的Bean实例

    • 适用于有状态的Bean

    • Spring不管理完整的生命周期,只负责初始化

  3. request(请求)

    • 每个HTTP请求创建一个新的Bean

    • 仅适用于Web应用

    • 请求结束时销毁

  4. session(会话)

    • 每个HTTP会话创建一个Bean

    • 仅适用于Web应用

    • 会话结束时销毁

  5. application(应用)

    • 每个ServletContext生命周期创建一个Bean

    • 类似单例,但范围是ServletContext而非Spring容器

  6. websocket(WebSocket)

    • 每个WebSocket会话创建一个Bean

    • 仅适用于WebSocket应用

2. 作用域配置示例

XML配置方式:
<bean id="accountService" class="com.example.AccountService" scope="prototype"/>
Java注解方式:
@Bean
@Scope("prototype")
public AccountService accountService() {return new AccountService();
}
使用@Scope注解:
@Service
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class PrototypeService {// ...
}

3. 作用域选择建议

  1. 无状态服务:使用singleton(默认),性能最佳

  2. 有状态组件:使用prototype,避免并发问题

  3. Web相关数据:根据需要使用request、session等作用域

  4. 线程安全考虑:prototype作用域可以避免线程安全问题,但会增加创建开销

4. 自定义作用域

Spring还允许注册自定义作用域:

public class ThreadScope implements Scope {// 实现Scope接口方法
}// 注册自定义作用域
ConfigurableBeanFactory factory = (ConfigurableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
factory.registerScope("thread", new ThreadScope());// 使用自定义作用域
@Bean
@Scope("thread")
public MyBean myBean() {return new MyBean();
}

三、生命周期与作用域的关系

不同作用域的Bean生命周期有所不同:

  1. singleton

    • 容器启动时初始化(默认懒加载除外)

    • 容器关闭时销毁

    • 完整的生命周期回调

  2. prototype

    • 每次请求时初始化

    • 容器不跟踪实例,不会调用销毁方法

    • 只有部分生命周期回调

  3. request/session

    • 请求/会话开始时初始化

    • 请求/会话结束时销毁

    • 完整的生命周期回调

四、最佳实践

  1. 尽量使用singleton作用域:性能最佳,适用于无状态服务

  2. 谨慎使用prototype:仅在必要时使用,注意资源释放

  3. 合理使用生命周期回调:资源初始化/释放放在合适的回调中

  4. 避免在singleton中注入prototype:会导致prototype失去意义,可以使用方法注入解决

  5. Web作用域Bean不要注入singleton:会导致状态不一致

五、总结

理解Spring Bean的生命周期和作用域对于开发高质量的Spring应用至关重要。通过合理利用生命周期回调和选择适当的作用域,可以构建出既高效又可靠的应用程序。记住,大多数情况下默认的singleton作用域是最佳选择,只有在确实需要时才使用其他作用域。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何将Excel表的内容转化为json格式呢?

文章目录 一、前言二、具体操作步骤 一、前言 先说一下我使用Excel表的内容转为json的应用场景&#xff0c;我们是用来处理国际化的时候用到的。 二、具体操作步骤 第一步&#xff1a;选择要转化Excel表的内容&#xff08;必须是key&#xff0c;value形式的&#xff09; 第二…

内存堆栈管理(Linux)

以问题形式讲解 1.每一个进程都有一个堆空间吗&#xff1f;还是多个进程共用一个堆空间&#xff1f; 在操作系统中&#xff0c;​​每个进程都有自己独立的虚拟地址空间&#xff0c;其中包括自己独占的堆空间。堆空间是进程私有的&#xff0c;不与其他进程共享。 进程之间的内…

ThreatLabz 2025 年人工智能安全报告

AI 应用趋势&#xff1a;爆发式增长与风险并存 2024 年&#xff0c;全球企业的 AI/ML 工具使用量呈指数级增长。Zscaler 云平台数据显示&#xff0c;2024 年 2 月至 12 月期间&#xff0c;AI/ML 交易总量达 5365 亿次&#xff0c;同比激增 3464.6%&#xff0c;涉及 800 多个应…

【Oracle学习笔记】7.存储过程(Stored Procedure)

Oracle中的存储过程是一组为了完成特定功能而预先编译并存储在数据库中的SQL语句和PL/SQL代码块。它可以接受参数、执行操作&#xff08;如查询、插入、更新、删除数据等&#xff09;&#xff0c;并返回结果。以下从多个方面详细讲解&#xff1a; 1. 存储过程的创建 创建存储过…

tc工具-corrupt 比 delay/loss 更影响性能

1. netem corrupt 5% 的作用 功能说明 corrupt 5% 表示 随机修改 5% 的数据包内容&#xff08;如翻转比特位&#xff09;&#xff0c;模拟数据损坏。它本身不会直接丢弃或延迟数据包&#xff0c;而是让接收端收到错误的数据&#xff08;可能触发校验和失败、协议层重传等&…

Flask YAML管理工具

项目概述 项目地址&#xff1a;https://github.com/KaiqiZing/Flask_Yaml_Demo 这是一个基于Flask开发的YAML文件管理工具&#xff0c;提供了完整的YAML文件查看、编辑、管理功能&#xff0c;具有现代化的Web界面和强大的编辑能力。 核心功能 1. 文件管理功能 目录扫描&am…

Embedding模型微调实战(ms-swift框架)

目录 简介 1. 创建虚拟环境 2 安装ms-swift 3安装其他依赖库 4. 下载数据集 5.开始embedding模型训练 6. 自定义数据格式和对应的Loss类型 &#xff08;1&#xff09; infoNCE损失 (2)余弦相似度损失 (3)对比学习损失 &#xff08;4).在线对比学习损失 &#…

从性能优化赛到社区Committer,走进赵宇捷在Apache Fory的成长之路

Apache Fory 是一个基于JIT和零拷贝的高性能多语言序列化框架&#xff0c;实现了高效紧凑的序列化协议&#xff0c;提供极致的性能、压缩率和易用性。在多语言序列化框架技术领域取得了重大突破&#xff0c;推动序列化技术步入高性能易用新篇章&#xff01;这一切&#xff0c;都…

Python实例题:基于 Flask 的任务管理系统

目录 Python实例题 题目 要求&#xff1a; 解题思路&#xff1a; 代码实现&#xff1a; Python实例题 题目 基于 Flask 的任务管理系统 要求&#xff1a; 使用 Flask 框架构建一个任务管理系统&#xff0c;支持以下功能&#xff1a; 用户认证&#xff08;注册、登录、…

利用GPU加速TensorFlow

一、写在前面 我们已经依靠keras和TensorFlow给大家做了一些机器学习在图像处理中的应用(影像组学学习手册,基于深度学习的图像分类任务)&#xff0c;此前的教程中我们没有用GPU进行加速&#xff0c;但是相较于CPU而言&#xff0c;GPU是设计用于处理大规模并行计算任务的硬件&…

模型预测专题:强鲁棒性DPCC

0 1 前言 在进行DPCC的学习过程中&#xff0c;于下面链接看到了一篇强鲁棒性算法&#xff1b;感觉挺有意思的&#xff0c;学习一下。 永磁同步电机高性能控制算法&#xff08;12&#xff09;——基于预测电流误差补偿的强鲁棒预测控制/参数辨识&有限集预测控制与连续集预…

修复opensuse 风滚草rabbitmq的Error: :plugins_dir_does_not_exist问题

https://wiki.archlinux.org/title/Talk:RabbitMQ 报错 yqh192 /u/l/r/l/r/plugins> sudo rabbitmq-plugins enable rabbitmq_management Error: :plugins_dir_does_not_exist Arguments given:enable rabbitmq_managementUsagerabbitmq-plugins [--node <node>] [--…

前端做gis地图有哪些库

以下是前端开发GIS地图常用的库&#xff1a; Leaflet&#xff1a;轻量级、易于使用的开源JavaScript库&#xff0c;具有丰富的地图功能和插件生态系统&#xff0c;支持多种地图数据源&#xff0c;适合初学者和专业开发者。其优势在于简洁性和易用性&#xff0c;代码结构清晰&am…

赋能城市安全韧性|众智鸿图总裁扈震受邀出席智慧城市大会发表主题报告

——“众智鸿图作为城市基础设施智能化综合服务提供商&#xff0c;以地理信息科学、时空大数据、人工智能为核心能力&#xff0c;长期深耕于燃气、供水、排水等城市基础设施生命线领域及港口、园区等工业领域&#xff0c;致力于为城市稳定运行与高效发展提供坚实保障。” 2025年…

【大语言模型入门】—— 浅析LLM基座—Transformer原理

【大语言模型入门】—— 浅析LLM基座—Transformer原理 解密GPT核心技术&#xff1a;Transformer架构深度解析被反复强调的核心概念意味着什么&#xff1f; GPT预测机制解析&#xff1a;从Next Token Prediction到任务推理核心机制的本质案例驱动的机制解析解构策略&#xff1a…

Django打造智能Web机器人控制平台

Django 实现 Web 机器人控制 以下是关于 Django 实现 Web 机器人控制管理的实例思路和关键代码片段,涵盖多个常见场景。由于篇幅限制,剩余的可通过类似模式扩展。 基础机器人模型定义 # models.py from django.db import modelsclass Robot(models.Model):name = models.C…

周赛98补题

题目意思&#xff1a; 给定一个数字判断加上自身任意因子数&#xff0c;是否能成为一个奇数。 思路&#xff1a; 我们想一个最简单的判断方法&#xff0c; 任意的数字的因子数都有1&#xff0c;故&#xff0c;最简单的方法就是判断奇偶。 奇数1成偶数&#xff0c;偶数1成奇…

【STM32】 STM32低功耗模式详解:睡眠模式与唤醒机制【待测试】

本篇知识点基于F0讲解 一、STM32三种低功耗模式参考表格 模式功耗唤醒时间保持状态典型应用场景睡眠模式中等 (mA级)最短 (μs级)CPU停止&#xff0c;外设保持短暂待机&#xff0c;快速响应停止模式低 (μA级)中等 (ms级)RAM保持&#xff0c;时钟停止长时间待机&#xff0c;电…

【Vue入门学习笔记】Vue核心语法

目录 准备工作删除不需要的代码 模版语法文本插值使用JavaScript表达式无效写法原始HTML 属性绑定简写布尔型Attribute动态绑定多个值 准备工作 删除不需要的代码 删除components下的文件 进入App.vue 删掉代码&#xff0c;只保留如下内容 <template></template&g…

ClickHouse 窗口分析 argMax() / argMin()

argMin() 是 ClickHouse 中一个非常有用的聚合函数&#xff0c;它可以找出某个列的最小值&#xff0c;并返回该最小值对应的另一个列的值 函数语法 argMin(arg, val) arg&#xff1a;要返回的列&#xff08;当找到最小值时返回该列的值&#xff09; val&#xff1a;用于比较的…