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 中有成员变量,多线程并发修改会出现数据错乱。
  • 配置注解:
java 复制代码
@Component
// 可省略,默认就是 singleton
@Scope("singleton")
public class UserService { }

2.prototype 多例

  • 规则每次从容器获取 Bean,都会创建全新实例,容器只负责创建,不管理生命周期。
  • 创建时机每次 getBean() / 依赖注入时创建
  • 销毁时机 :Spring 容器不负责销毁,由 JVM GC 回收。
  • 使用场景:有状态 Bean、实体对象、请求级临时对象、非共享实例。
  • 易错点:单例 Bean(Service/Controller)中注入多例 Bean,多例会失效。因为单例仅启动时注入一次依赖,后续不会刷新。
  • 解决方案:通过 ApplicationContext 手动获取、使用 ObjectProvider
  • 配置注解:
java 复制代码
@Component
@Scope("prototype")
public class Order { }

3.request 请求域(Web 环境专属)

  • 核心规则 :每一次 HTTP 请求,都会创建一个全新的 Bean 实例;请求处理完毕,Bean 立即销毁
  • 生命周期:跟随 HTTP 请求,最短、最临时的 Web 作用域。
  • 使用场景:存储单次请求专属临时数据、请求上下文、请求参数封装、单次请求日志追踪信息。
  • 注解配置
java 复制代码
@Component
@Scope("request")
public class RequestContext {
    // 存储本次请求的请求ID、客户端IP、请求时间等临时数据
    private String requestId;
    private String clientIp;
}

4.session 会话域(Web 环境专属)

  • 核心规则 :同一个用户浏览器 Session 会话,对应唯一一个 Bean 实例;会话过期、浏览器关闭、Session 失效,Bean 自动销毁

  • 生命周期:跟随用户会话,贯穿用户多次接口请求。

  • 使用场景:存储用户会话级数据,如登录用户信息、临时会话缓存、权限临时标识、用户行为记录。

  • 底层特点 :Bean 绑定 HttpSession,不同用户会话数据完全隔离。

  • 注解配置

java 复制代码
@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容器销毁时统一释放

  • 注解配置

java 复制代码
@Component
@Scope("application")
public class SystemGlobalConfig {
    // 项目全局配置,全应用共享
    private String projectName;
    private Integer maxUploadSize;
}

6.websocket 长连接域(Web 环境专属)

  • 核心规则 :每一条 WebSocket 长连接,对应一个独立 Bean 实例;连接断开、客户端下线,Bean 立即销毁
  • 使用场景:即时通讯、消息推送、在线聊天室、实时数据监控、长连接状态存储。
  • 注解配置代码
java 复制代码
@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生效)。
相关推荐
周末也要写八哥7 小时前
线程的生命周期之线程睡眠
java·开发语言·jvm
炸薯条!7 小时前
二叉树的链式表示(2)
java·数据结构·算法
徐寿春7 小时前
什么是数据倾斜
java·guava
李白的天不白7 小时前
一个服务器可以搭建多个网站
java·tomcat
●VON7 小时前
AtomGit Flutter鸿蒙客户端:共享组件
java·flutter·华为·harmonyos·鸿蒙
程序猿乐锅7 小时前
【JAVASE | 第十七篇】Java 网络通信
java·开发语言
执于代码7 小时前
Java交互打印的问题
java
我命由我123458 小时前
Windows 操作系统 - Windows 查看防火墙是否开启、Windows 查看防火墙放行端口
java·运维·开发语言·windows·java-ee·操作系统·运维开发
fly spider8 小时前
Spring 原理总览:从启动到请求执行
java·数据库·spring
大大杰哥8 小时前
SSeEmitter的基本使用和介绍
java·sse·通信