bean的作用域与生命周期
一、Bean的作用域
1.1 什么是Bean作用域?
简单来说,Bean作用域是Spring用来控制Bean实例创建数量、对象存活范围的核心机制。
一句话区分:从Spring容器中取Bean,是一直用同一个对象,还是每次都新建对象,全部由作用域决定。
Spring内置一共6种作用域,分为:4种通用作用域 + 2种Web专属作用域。通用作用域可用于所有Spring项目,Web专属作用域仅适用于Web工程。
1.2 六大作用域详细汇总
作用域类型 | 核心含义 | 实例数量 | 适用场景 |
|---|---|---|---|
singleton(默认) | 单例作用域,整个Spring容器全局仅存在一个Bean实例 | 全局1个 | 无状态Bean,日常开发绝大多数场景:Service、Controller、Dao、工具类 |
prototype | 原型多例作用域,每次获取、注入Bean都会新建对象 | 多个 | 有状态Bean、需要独立对象、避免数据共享冲突的场景 |
request | 一次HTTP请求对应一个独立Bean实例 | 请求级 | Web项目,存储单次请求的临时数据 |
session | 一个用户会话对应一个Bean实例 | 会话级 | 存储用户登录状态、会话缓存数据 |
application | 整个Web应用全局唯一,和项目容器同生命周期 | 全局1个 | 项目全局配置、公共常量、全局参数 |
websocket | 一个WebSocket长连接对应一个Bean实例 | 连接级 | 即时通讯、消息推送、WebSocket长连接业务 |
1.3 核心作用域代码实战(开发常用)
实际开发中,我们使用最多的只有singleton(单例)和prototype(多例),其余Web专属作用域仅在特殊业务场景中使用。
1、singleton 单例(默认作用域)
Spring容器启动初始化阶段就会创建单例Bean,全局共享同一个对象,程序中所有注入、获取Bean的操作,拿到的都是同一个实例。
核心特点:容器启动初始化、全局唯一、性能高、非线程安全
2、prototype 多例(原型作用域)
多例Bean不会在容器启动时初始化,每次注入、调用getBean()获取Bean时,都会全新创建一个对象。
核心特点:多实例、线程安全、Spring不管理多例Bean的初始化和销毁生命周期
二、Bean完整生命周期
Bean生命周期,就是Bean在Spring IoC容器中从创建、赋值、初始化、使用到最终销毁的完整全过程。
这是Java后端面试高频必考知识点,同时也是解决Spring Bean注入报错、初始化异常、对象失效等问题的核心底层依据!
2.1 整体执行流程
容器启动 → 实例化 → 属性赋值 → Aware回调 → 前置处理器 → 初始化 → 后置处理器 → 就绪使用 → 容器关闭销毁
2.2 七步流程详细拆解
第一步:实例化(new空对象)
Spring IoC容器启动后,通过反射机制调用类的无参构造方法,为Bean创建一个空对象,完成实例化操作。
💡 重点:自定义Bean类如果没有无参构造方法,会直接抛出异常,导致Bean创建失败!
第二步:属性赋值(依赖注入)
容器通过setter方法、构造器注入、@Autowired注解等多种方式,为实例化后的空对象完成成员变量赋值,实现依赖注入。
💡 日常开发中常见的“找不到setter方法”“依赖注入失败”报错,基本都出在这一步。
第三步:Aware接口容器回调
Spring提供内置扩展接口,让Bean具备感知Spring容器资源的能力,完成容器资源的绑定:
BeanNameAware:获取当前Bean的名称/id
BeanFactoryAware:获取当前Bean工厂对象
ApplicationContextAware:获取Spring全局上下文对象
第四步:Bean前后置处理器增强
BeanPostProcessor(Bean后置处理器)是Spring的全局核心增强机制,也是Spring AOP、注解功能增强的底层原理。会在Bean初始化前后,执行自定义的前置、后置处理逻辑。
第五步:自定义初始化逻辑
Spring提供三种自定义Bean初始化逻辑的方式,执行优先级从高到低:
@PostConstruct 注解(开发推荐,简洁高效)
实现InitializingBean接口
XML配置 init-method 属性
第六步:Bean就绪使用
所有初始化流程执行完毕后,完整的Bean对象会被存入Spring单例池,正式就绪,对外提供业务调用服务。
第七步:容器关闭销毁
仅单例Bean会被Spring容器管理销毁,多例Bean由JVM垃圾回收管理。Spring提供两种销毁逻辑实现方式:
@PreDestroy 注解
实现DisposableBean接口
2.3 完整生命周期代码演示
以下代码可直接复制运行,控制台会精准打印每一步的执行顺序,直观看懂Bean完整生命周期:
import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.DisposableBean; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; /** * Spring Bean 完整生命周期测试 * @author 个人博客 */ public class LifeCycleBean implements BeanNameAware, InitializingBean, DisposableBean { // 1. 实例化:执行无参构造创建空对象 public LifeCycleBean() { System.out.println("1、Bean实例化:执行无参构造"); } // 3. Aware接口回调:获取Bean名称 @Override public void setBeanName(String name) { System.out.println("3、Aware接口回调:Bean名称 = " + name); } // 4. 注解初始化(优先级最高) @PostConstruct public void postConstruct() { System.out.println("5、初始化:@PostConstruct 执行"); } // 5. 接口初始化 @Override public void afterPropertiesSet() throws Exception { System.out.println("5、初始化:InitializingBean 执行"); } // 销毁方法1:注解销毁 @PreDestroy public void preDestroy() { System.out.println("7、销毁:@PreDestroy 执行"); } // 销毁方法2:接口销毁 @Override public void destroy() throws Exception { System.out.println("7、销毁:DisposableBean 执行"); } }2.4 生命周期最终执行顺序
无参构造实例化 → 属性赋值 → Aware接口回调 → Bean前置处理器 → @PostConstruct → InitializingBean → init-method → Bean后置处理器 → Bean使用阶段 → 容器关闭销毁
三、作用域与生命周期关联关系
很多同学会混淆两者的关联,这里做精准总结,区分不同作用域Bean的生命周期差异:
singleton单例Bean:容器启动时完成实例化、赋值、全部初始化流程,容器关闭时触发销毁,完整生命周期全程由Spring IoC容器管理
prototype多例Bean:仅在调用获取时创建对象,Spring只负责实例化和属性赋值,不管理初始化、销毁流程,对象生命周期由JVM全权管理
Web专属作用域Bean(request/session/application/websocket):生命周期跟随HTTP请求、用户会话、WebSocket长连接,一旦请求结束、会话过期、连接断开,Bean自动销毁
四、全文总结
1、Bean作用域的核心作用是控制Bean的实例数量和存活范围,日常开发99%场景仅使用单例、多例两种作用域;
2、单例Bean性能优异但非线程安全,适合无状态业务;多例Bean线程安全但创建开销更大,适合有状态业务;
3、Bean完整生命周期是Spring IoC的核心底层逻辑,熟记七步执行流程,可解决绝大多数Bean注入、初始化、报错问题;
4、Spring容器只全权管理单例Bean的完整生命周期,多例Bean仅负责创建赋值,不负责后续生命周期管理。
