Spring Bean作用域以及生命周期
前言
在之前已经有几篇文章来讲解过Bean的创建和依赖注入等相关内容,这篇文章补充一下关于Bean的一些重要内容:Bean作用域和生命周期
一、Bean作用域
1.定义
作用域 = Spring 容器创建 Bean 的「实例数量」和「存活范围」
它决定了:
整个项目有几个这个 Bean 对象?
什么时候创建?
什么时候销毁?
是否线程共享?
2.分类
Spring 6主流提供六种内置作用域,日常开发常用前四种
- singleton(单例,默认)
- prototype(多例)
- request(请求域)
- session(会话域)
- application(应用域)
- websocket(长连接域)
二、六大作用域详解
配置指定作用域使用注解@Scope
1.singleton 单例(默认作用域)
- 规则:整个 Spring IoC 容器中仅存在一个 Bean 实例,全局共享。
- 创建时机:
- 默认:容器启动时立即初始化(饿汉式)
- 配合
lazy-init="true":第一次获取 Bean 时才创建(懒加载)
- 销毁时机:IoC 容器关闭时销毁。
- 使用场景:无状态 Bean(Service、Mapper、Controller、工具类),绝大多数业务组件。
- 注意:单例 Bean 非线程安全。如果 Bean 中有成员变量,多线程并发修改会出现数据错乱。
- 配置注解:
@Component // 可省略,默认就是 singleton @Scope("singleton") public class UserService { }2.prototype 多例
- 规则:每次从容器获取 Bean,都会创建全新实例,容器只负责创建,不管理生命周期。
- 创建时机:每次
getBean()/ 依赖注入时创建。 - 销毁时机:Spring 容器不负责销毁,由 JVM GC 回收。
- 使用场景:有状态 Bean、实体对象、请求级临时对象、非共享实例。
- 易错点:单例 Bean(Service/Controller)中注入多例 Bean,多例会失效。因为单例仅启动时注入一次依赖,后续不会刷新。
- 解决方案:通过
ApplicationContext手动获取、使用ObjectProvider。 - 配置注解:
@Component @Scope("prototype") public class Order { }3.request 请求域(Web 环境专属)
- 核心规则:每一次 HTTP 请求,都会创建一个全新的 Bean 实例;请求处理完毕,Bean 立即销毁。
- 生命周期:跟随 HTTP 请求,最短、最临时的 Web 作用域。
- 使用场景:存储单次请求专属临时数据、请求上下文、请求参数封装、单次请求日志追踪信息。
- 注解配置:
@Component @Scope("request") public class RequestContext { // 存储本次请求的请求ID、客户端IP、请求时间等临时数据 private String requestId; private String clientIp; }4.session 会话域(Web 环境专属)
- 核心规则:同一个用户浏览器 Session 会话,对应唯一一个 Bean 实例;会话过期、浏览器关闭、Session 失效,Bean 自动销毁。
- 生命周期:跟随用户会话,贯穿用户多次接口请求。
- 使用场景:存储用户会话级数据,如登录用户信息、临时会话缓存、权限临时标识、用户行为记录。
底层特点:Bean 绑定
HttpSession,不同用户会话数据完全隔离。注解配置:
@Component @Scope("session") public class UserSessionInfo { // 存储当前登录用户信息,单用户会话共享 private Long userId; private String username; private String token; }5.application 应用域(Web 环境专属)
- 核心规则:整个 Web 应用全局仅存在一个 Bean 实例,生命周期与
ServletContext完全一致。 - 关键区别(高频面试):
singleton:仅单个 Spring IoC 容器内单例
application:整个 Web 应用、跨 Spring 容器全局单例,作用域范围更大
- 使用场景:存储项目全局公共数据、系统配置、全局统计数据、公共常量缓存。
- 销毁时机:项目停止、Web容器销毁时统一释放
- 注解配置:
@Component @Scope("application") public class SystemGlobalConfig { // 项目全局配置,全应用共享 private String projectName; private Integer maxUploadSize; }6.websocket 长连接域(Web 环境专属)
- 核心规则:每一条 WebSocket 长连接,对应一个独立 Bean 实例;连接断开、客户端下线,Bean 立即销毁。
- 使用场景:即时通讯、消息推送、在线聊天室、实时数据监控、长连接状态存储。
- 注解配置代码:
@Component @Scope("websocket") public class WebSocketSessionBean { // 存储单条长连接专属信息 private String sessionId; private Long connectUserId; private LocalDateTime connectTime; }三、Spring Bean生命周期
Spring Bean生命周期,是Spring IoC容器对Bean从创建、初始化、对外服务到最终销毁的全流程管控。整个过程核心分为实例化、属性赋值、初始化、销毁四大阶段,涵盖反射创建对象、DI依赖注入、Aware接口回调、初始化方法执行、AOP动态代理、容器销毁回收等核心底层逻辑。
1.阶段一:Bean实例化(造对象)
实例化是Bean生命周期的第一步,核心目的:通过底层机制创建Bean的原始空对象,此时对象仅被分配内存,尚未赋值、未完成初始化。
Spring 提供三种实例化方式,优先级与场景各有不同:
(1)反射构造函数实例化(最常用)
Spring 自动推断Bean的可用构造方法,通过JDK反射机制创建对象。
如果Bean存在无参构造,默认优先使用无参构造实例化;
如果仅有有参构造,Spring会自动触发构造器注入,完成实例化;
这是日常开发中@Component、@Service等注解Bean的默认实例化方式。
(2)静态工厂实例化
通过工厂类的静态方法创建Bean对象,无需创建工厂实例,直接调用静态方法生成目标Bean,多用于框架内置工具类、静态资源Bean的创建。
(3)实例工厂实例化
需要先创建工厂Bean实例,再通过工厂实例的普通方法创建目标Bean,灵活性更高,可根据工厂实例的状态动态生成不同Bean对象。
2.阶段二:属性赋值(DI依赖注入)
实例化完成后,Spring进入依赖注入阶段,也是IoC容器的核心价值体现。此阶段核心目的:解析Bean的依赖关系,自动完成属性赋值,让Bean具备完整的依赖资源。
(1)四大自动装配规则
Spring默认提供四种装配模式,日常开发核心使用byType,配合@Autowired注解实现自动装配:
byType(按类型装配):默认主流模式,根据属性类型匹配容器中的Bean,@Autowired默认基于此实现;
byName(按名称装配):根据属性名与Bean的id/name匹配赋值;
constructor(构造器装配):通过有参构造完成依赖注入,Spring4.3后优先推荐;
none(不自动装配):关闭自动装配,需手动配置依赖。
(2) 核心难点:循环依赖问题
循环依赖只发生在属性赋值阶段,是此阶段最核心的底层考点。
场景:A依赖B、B依赖A,Spring在递归赋值时会产生循环引用。
Spring通过三级缓存机制,完美解决单例Bean、setter/字段注入的循环依赖问题;但无法解决多例Bean、构造器注入的循环依赖。
3.阶段三:初始化(增强与加工对象)
属性赋值完成后,Bean的依赖已经就绪,Spring开始对Bean进行自定义加工、生命周期回调、动态代理增强,是Bean从“可用对象”变成“完整业务对象”的关键阶段。整个初始化分为三步,执行顺序固定。
(1) 第一步:XXXAware接口回调(容器感知)
如果Bean实现了Spring内置的Aware感知接口,Spring会自动执行对应回调方法,让普通Bean拥有感知容器资源的能力。
常用核心Aware接口:
BeanNameAware:感知自身Bean名称;
BeanFactoryAware:感知所属Bean工厂;
ApplicationContextAware:感知Spring应用上下文。
未实现Aware接口的Bean,直接跳过此步骤。
(2)第二步:自定义初始化生命周期回调
Spring提供三种初始化方式,执行顺序固定、优先级不可逆,用于开发者自定义Bean初始化业务逻辑(如参数校验、资源初始化、缓存预热等):
@PostConstruct注解(JSR标准,优先级最高)
InitializingBean#afterPropertiesSet接口方法(Spring内置)
@Bean(initMethod = "xxx")自定义初始化方法(优先级最低)
(3)第三步:AOP动态代理创建(核心增强)
初始化收尾阶段,Spring会判断当前Bean是否需要AOP切面增强:
如果Bean存在匹配的切面规则,Spring在此阶段生成动态代理对象(JDK动态代理/CGLIB代理),最终放入容器的是代理Bean;
如果无需AOP增强,直接使用原始Bean对象。
4.阶段四:销毁(容器关闭回收资源)
Bean销毁是生命周期的最后一步,仅针对单例Bean(singleton)生效,多例Bean(prototype)由JVM GC回收,Spring容器不负责管理销毁。
(1)触发时机
仅在Spring IoC容器关闭时触发(项目停机、上下文close、应用销毁)。
(2)销毁生命周期回调(执行顺序固定)
与初始化逻辑对应,三种销毁方式优先级固定,用于释放资源(关闭连接、清空缓存、停止线程等):
@PreDestroy注解(优先级最高)
DisposableBean#destroy接口方法(Spring内置)
@Bean(destroyMethod = "xxx")自定义销毁方法(优先级最低)
5.整个过程总结
- 实例化:反射/工厂创建原始空对象,只分配内存,无赋值无逻辑;
- 属性赋值:完成DI自动装配,解决依赖关系,触发循环依赖处理;
- 初始化:Aware容器感知 → 自定义初始化逻辑 → AOP动态代理增强,生成成品Bean;
- 销毁:容器关闭时执行销毁回调,优雅释放资源(仅单例Bean生效)。
