Spring bean 的生命周期、注入方式和作用域
一、Spring Bean的生命周期
Spring Bean的生命周期是指从Bean的定义加载到最终销毁的整个过程,Spring框架在每个阶段都提供了钩子方法,允许开发者在特定时机执行自定义逻辑。
1. Bean定义加载阶段
容器启动时加载配置(XML/注解/JavaConfig),解析@Component、@Bean等注解或XML配置,生成BeanDefinition。BeanDefinition是描述Bean的元数据对象,包含类名、作用域、初始化方法、属性值、依赖关系等信息。
2. Bean实例化阶段
Spring容器根据BeanDefinition创建Bean实例,通常通过反射机制实现。例如,对于UserService
类,Spring会使用类似Class.forName("com.example.UserService").newInstance()
的方式创建对象实例。
3. 属性填充阶段
在实例化之后,Spring会将依赖的其他Bean注入到当前Bean中。例如,如果UserService
依赖于UserRepository
,Spring会查找并将UserRepository
的实例注入到UserService
中。
4. 初始化回调阶段
Bean可以实现InitializingBean
接口,在afterPropertiesSet
方法中编写初始化逻辑。也可以通过以下方式实现初始化回调:
public class ExampleBean implements InitializingBean {public void afterPropertiesSet() {// 初始化逻辑}
}
或使用@PostConstruct
注解标记初始化方法420。
5. 销毁阶段
在容器关闭时,Spring会调用实现了DisposableBean
接口的Bean的destroy()
方法,或使用@PreDestroy
注解标记的方法执行清理工作。
二、Spring Bean的注入方式
Spring支持多种依赖注入方式,每种方式有其适用场景和优缺点。
1. 构造器注入(Constructor Injection)
通过类的构造函数注入依赖,是Spring官方推荐的方式,尤其是在Spring 4.3及以上版本中。
特点:
- 不可变性:依赖项在对象创建时注入,之后不可更改
- 强依赖:明确表示类的依赖关系
- 易于测试:便于单元测试
- 避免循环依赖:如果存在循环依赖,Spring会抛出异常
示例代码:
@Service
public class UserService {private final UserRepository userRepository;@Autowiredpublic UserService(UserRepository userRepository) {this.userRepository = userRepository;}
}
2. Setter注入(Setter Injection)
通过setter方法注入依赖,适用于可选依赖或需要在对象创建后进行依赖设置的情况。
特点:
- 灵活性高:支持可选依赖
- 解决循环依赖:Spring容器可处理Setter注入的循环依赖
- 向后兼容:适合逐步迁移旧代码到依赖注入模式
示例代码:
@Service
public class OrderService {private PaymentProcessor paymentProcessor;@Autowiredpublic void setPaymentProcessor(PaymentProcessor paymentProcessor) {this.paymentProcessor = paymentProcessor;}
}
3. 字段注入(Field Injection)
直接在类的字段上使用注解注入依赖,虽然代码简洁但不被推荐。
特点:
- 代码简洁
- 可能导致循环依赖
- 不利于单元测试
- 无法使用final修饰符
4. 方法注入(Method Injection)
一种特殊的注入方式,主要用于解决单例Bean中需要原型Bean的情况。
实现方式:
- 实现
ApplicationContextAware
接口,手动获取Bean - 使用
@Lookup
注解标记方法
示例代码:
@Component
public class CommandManager implements ApplicationContextAware {private ApplicationContext applicationContext;public Object process(Map<String, Object> params) {Command command = createCommand();command.setStateMap(params);return command.execute();}protected Command createCommand() {return applicationContext.getBean(Command.class);}
}
三、Spring Bean的作用域
Spring Bean的作用域决定了Bean实例的创建方式和生命周期管理。
1. 标准作用域
作用域 | 描述 | 适用场景 |
---|---|---|
singleton | 整个容器中只有一个实例 | 无状态Bean,Spring默认作用域 |
prototype | 每次请求都创建新实例 | 有状态Bean |
2. Web相关作用域
作用域 | 描述 | 适用场景 |
---|---|---|
request | 每个HTTP请求创建一个新实例 | Web请求处理 |
session | 每个用户会话创建一个实例 | 用户会话数据 |
application | ServletContext生命周期 | 全局应用数据 |
3. 自定义作用域
Spring允许开发者创建自定义作用域,例如线程级作用域或多租户系统中的租户级作用域22。
实现步骤:
- 实现
Scope
接口 - 注册自定义作用域到容器
- 在Bean定义中使用自定义作用域
4. 作用域与生命周期的关系
不同作用域的Bean在生命周期管理上有显著差异:
- singleton Bean:在容器启动时创建,容器关闭时销毁
- prototype Bean:每次请求时创建,由调用者负责销毁
- request/session Bean:在请求/会话开始时创建,在请求/会话结束时销毁
四、最佳实践与最新特性(2025)
1. 注入方式选择
- 强制依赖:优先使用构造器注入
- 可选依赖:考虑使用Setter注入
- 避免使用:字段注入,特别是在新项目中
2. 生命周期管理
- 使用
@PostConstruct
和@PreDestroy
注解管理初始化和销毁逻辑,而不是实现InitializingBean
和DisposableBean
接口 - 对于持有外部资源(如数据库连接)的Bean,务必实现销毁逻辑
3. 作用域选择
- 默认使用singleton作用域
- 有状态对象使用prototype作用域
- Web相关数据使用request/session作用域
相关文章:
Spring bean 的生命周期、注入方式和作用域
一、Spring Bean的生命周期 Spring Bean的生命周期是指从Bean的定义加载到最终销毁的整个过程,Spring框架在每个阶段都提供了钩子方法,允许开发者在特定时机执行自定义逻辑。 1. Bean定义加载阶段 容器启动时加载配置(XML/注解/JavaConfig)࿰…...
Python爬虫(26)Python爬虫高阶:Scrapy+Selenium分布式动态爬虫架构实践
目录 一、背景:动态爬虫的工程化挑战二、技术架构设计1. 系统架构图2. 核心组件交互 三、环境准备与项目搭建1. 安装依赖库2. 项目结构 四、核心模块实现1. Selenium集成到Scrapy(中间件开发)2. 分布式配置(settings.py࿰…...

Python 之类型注解
类型注解允许开发者显式地声明变量、函数参数和返回值的类型。但是加不加注解对于程序的运行没任何影响(是非强制的,且类型注解不影响运行时行为),属于 有了挺好,没有也行。但是大型项目按照规范添加注解的话ÿ…...

【linux】Web服务—搭建nginx+ssl的加密认证web服务器
准备工作 步骤: 一、 新建存储网站数据文件的目录 二、创建一个该目录下的默认页面,index.html 三、使用算法进行加密 四、制作证书 五、编辑配置文件,可以选择修改主配置文件,但是不建议 原因如下: 自定义一个配置文…...

基于HTTP头部字段的SQL注入:SQLi-labs第17-20关
前置知识:HTTP头部介绍 HTTP(超文本传输协议)头部(Headers)是客户端和服务器在通信时传递的元数据,用于控制请求和响应的行为、传递附加信息或定义内容类型等。它们分为请求头(Request Headers&…...

实战解析MCP-使用本地的Qwen-2.5模型-AI协议的未来?
文章目录 目录 文章目录 前言 一、MCP是什么? 1.1MCP定义 1.2工作原理 二、为什么要MCP? 2.1 打破碎片化的困局 2.2 实时双向通信,提升交互效率 2.3 提高安全性与数据隐私保护 三、MCP 与 LangChain 的区别 3.1 目标定位不同 3.…...
SRS流媒体服务器(5)源码分析之RTMP握手
1.概述 学习 RTMP 握手逻辑前,需明确两个核心问题: rtmp协议连接流程阶段rtmp简单握手和复杂握手区别 具体可以学习往期博客: RTMP协议分析_rtmp与264的关系-CSDN博客 2.rtmp握手源码分析 2.1 握手入口 根据SRS流媒体服务器(4)可知&am…...
内核性能测试(60s不丢包性能)
以xGAP-200-SE7K-L(双口10G)在飞腾D2000上为例(单通道最高性能约2.8Gbps) 单口测试 0口: tcp: taskset -c 4 iperf -c 1.1.1.1 -i 1 -t 60 -p 60001 taskset -c 4 iperf -s -i 1 -p 60001 udp: taskse…...

RabbitMQ高级篇-MQ的可靠性
目录 MQ的可靠性 1.如何设置数据持久化 1.1.交换机持久化 1.2.队列持久化 1.3.消息持久化 2.消息持久化 队列持久化: 消息持久化: 3.非消息持久化 非持久化队列: 非持久化消息: 4.消息的存储机制 4.1持久化消息&…...
MySQL 数据库集群部署、性能优化及高可用架构设计
MySQL 数据库集群部署、性能优化及高可用架构设计 集群部署方案 1. 主从复制架构 传统主从复制:配置一个主库(Master)和多个从库(Slave)GTID复制:基于全局事务标识符的复制,简化故障转移半同步复制:确保至少一个从库接收到数据…...

fpga系列 HDL : Microchip FPGA开发软件 Libero Soc 项目仿真示例
新建项目 项目初始界面中创建或导入设计文件: 新建HDL文件 module test (input [3:0] a,input [3:0] b,output reg [3:0] sum,output reg carry_out );always (*) begin{carry_out, sum} a b; endendmodule点击此按钮可进行项目信息的重新…...
将单链表反转【数据结构练习题】
- 第 98 篇 - Date: 2025 - 05 - 16 Author: 郑龙浩/仟墨 反转单链表(出现频率非常的高) 文章目录 反转单链表(出现频率非常的高)题目:反转一个链表思路:代码实现(第3种思路): 题目:反转一个链表 将 1->2->3->4->5->NULL反转…...

DeepSearch:WebThinker开启AI搜索研究新纪元!
1,项目简介 WebThinker 是一个深度研究智能体,使 LRMs 能够在推理过程中自主搜索网络、导航网页,并撰写研究报告。这种技术的目标是革命性的:让用户通过简单的查询就能在互联网的海量信息中进行深度搜索、挖掘和整合,从…...

springCloud/Alibaba常用中间件之Setinel实现熔断降级
文章目录 SpringCloud Alibaba:依赖版本补充Sentinel:1、下载-运行:Sentinel(1.8.6)下载sentinel:运行:Sentinel <br> 2、流控规则① 公共的测试代码以及需要使用的测试Jmeter①、流控模式1. 直接:2. 并联:3. 链路: ②、流控效果1. 快速…...
从裸机开发到实时操作系统:FreeRTOS详解与实战指南
从裸机开发到实时操作系统:FreeRTOS详解与实战指南 本文将带你从零开始,深入理解嵌入式系统中的裸机开发与实时操作系统,以FreeRTOS为例,全面剖析其核心概念、工作原理及应用场景。无论你是嵌入式新手还是希望提升技能的开发者&am…...

Deeper and Wider Siamese Networks for Real-Time Visual Tracking
现象: the backbone networks used in Siamese trackers are relatively shallow, such as AlexNet , which does not fully take advantage of the capability of modern deep neural networks. direct replacement of backbones with existing powerful archite…...
简单介绍C++中线性代数运算库Eigen
Eigen 是一个高性能的 C 模板库,专注于线性代数、矩阵和向量运算,广泛应用于科学计算、机器学习和计算机视觉等领域。以下是对 Eigen 库的详细介绍: 1. 概述 核心功能:支持矩阵、向量运算,包括基本算术、矩阵分解&…...
Python爬虫实战:研究decrypt()方法解密
1. 引言 1.1 研究背景与意义 在当今数字化时代,网络数据蕴含着巨大的价值。然而,许多网站为了保护其数据安全和商业利益,会采用各种加密手段对传输的数据进行处理。这些加密措施给数据采集工作带来了巨大挑战。网络爬虫逆向解密技术应运而生,它通过分析和破解网站的加密机…...

黑马程序员C++2024版笔记 第0章 C++入门
1.C代码的基础结构 以hello_world代码为例: 预处理指令 #include<iostream> using namespace std; 代码前2行是预处理指令,即代码编译前的准备工作。(编译是将源代码转化为可执行程序.exe文件的过程) 主函数 主函数是…...
c#定义占用固定字节长度的结构体字段
在c中,经常类似这样定义结构体: struct DEMO_STRUCT {int a;int b;char c[128]; }; 定义这个结构体,占用了136个字节的内存空间,关键的是,它的内存块是连续的,其中c占用了128个字节 然后如果想在c#中定义…...

foxmail - foxmail 启用超大附件提示密码与帐号不匹配
foxmail 启用超大附件提示密码与帐号不匹配 问题描述 在 foxmail 客户端中,启用超大附件功能,输入了正确的账号(邮箱)与密码,但是提示密码与帐号不匹配 处理策略 找到 foxmail 客户端目录/Global 目录下的 domain.i…...

Crowdfund Insider聚焦:CertiK联创顾荣辉解析Web3.0创新与安全平衡之术
近日,权威金融科技媒体Crowdfund Insider发布报道,聚焦CertiK联合创始人兼CEO顾荣辉教授在Unchained Summit的主题演讲。报道指出,顾教授的观点揭示了Web3.0生态当前面临的挑战,以及合规与技术在推动行业可持续发展中的关键作用。…...
EDR与XDR如何选择适合您的网络安全解决方案
1. 什么是EDR? 端点检测与响应(EDR) 专注于保护端点设备(如电脑、服务器、移动设备)。通过在端点安装代理软件,EDR实时监控设备活动,检测威胁并快速响应。 EDR核心功能 实时监控:…...

PowerBI链接EXCEL实现自动化报表
PowerBI链接EXCEL实现自动化报表 曾经我将工作中一天的工作缩短至2个小时,其中最关键的一步就是使用PowerBI链接Excel做成一个自动化报表,PowerBI更新源数据,Excel更新报表并且保留报表格式。 以制作一个超市销售报表为例,简单叙…...

腾讯云MCP数据智能处理:简化数据探索与分析的全流程指南
引言 在当今数据驱动的商业环境中,企业面临着海量数据处理和分析的挑战。腾讯云MCP(Managed Cloud Platform)提供的数据智能处理解决方案,为数据科学家和分析师提供了强大的工具集,能够显著简化数据探索、分析流程,并增强数据科学…...

Android framework 中间件开发(一)
在Android开发中,经常会调用到一些系统服务,这些系统服务简化了上层应用的开发,这便是中间件的作用,中间件是介于系统和应用之间的桥梁,将复杂的底层逻辑进行一层封装,供上层APP直接调用,或者将一些APP没有权限一些操作放到中间件里面来实施. 假设一个需求,通过中间件调节系统亮…...
Lua中使用module时踩过的坑
在lua中设置某个全局对象(假如对象名为LDataUser)为nil时, LDataUser并不会变成nil, 但在有些情况下设置LDataUser nil时却真变成了nil,然后会导致后续再使用LDataUser时会抛nil异常, 后来发现是使用module搞的鬼,下面看看豆包AI给的解释,还…...

MATLAB中的概率分布生成:从理论到实践
MATLAB中的概率分布生成:从理论到实践 引言 MATLAB作为一款强大的科学计算软件,在统计分析、数据模拟和概率建模方面提供了丰富的功能。本文将介绍如何使用MATLAB生成各种常见的概率分布,包括均匀分布、正态分布、泊松分布等,并…...

C# 面向对象 构造函数带参无参细节解析
继承类构造时会先调用基类构造函数,不显式调用基类构造函数时,默认调用基类无参构造函数,但如果基类没有写无参构造函数,会无法调用从而报错;此时,要么显式的调用基类构造函数,并按其格式带上参…...
轨迹误差评估完整流程总结(使用 evo 工具)
roslaunch .launch rosbag play your_dataset.bag -r 2.0 ✅ 第二步:录制估计轨迹 bash 复制编辑 rosbag record -O traj_only.bag /aft_mapped_to_init 运行一段时间后 CtrlC 停止,生成 traj_only.bag 第三步:提取估计轨迹和真值轨迹为…...