Spring Bean的生命周期说一下,单例Bean是否线程安全?

2025年 阅读约 8 分钟 面试指南 · Spring Boot面试

Spring Bean生命周期全流程解析,深入探讨单例Bean线程安全问题及四种解决方案。

一句话总结

Bean生命周期:实例化 → 属性填充 → 初始化 → 销毁。单例Bean本身不保证线程安全,需根据是否有状态采取不同方案:无状态Bean安全,有状态Bean需用局部变量、ThreadLocal、同步或Prototype作用域。

初级理解

Bean生命周期核心步骤:

1. 实例化:通过反射创建Bean对象 2. 属性填充:依赖注入(DI),完成Aware接口回调 3. 初始化:BeanPostProcessor前置处理 → InitializingBean.afterPropertiesSet() → 自定义init-method → BeanPostProcessor后置处理(AOP代理在此生成) 4. 销毁:DisposableBean.destroy() → 自定义destroy-method
一句话总结:实例化 → 属性填充 → 初始化 → 销毁。

中级深入

单例Bean线程安全问题:

Spring单例Bean本身不保证线程安全。 • 无状态Bean(Service、DAO,无成员变量)→ 线程安全 • 有状态Bean(含可写成员变量)→ 线程不安全

四种解决方案:

1. 使用局部变量:方法内定义变量,无线程安全问题 2. 使用ThreadLocal:每个线程有自己的变量副本 3. 同步机制:synchronized/Lock 4. 将Bean改为Prototype作用域:每次请求创建新实例
注意:Spring默认使用单例作用域,如果Bean有状态且需要线程安全,必须采取措施。

高级拓展

为什么默认单例?

单例避免了频繁创建与销毁对象的开销,减少GC压力,提升性能。同时单例天然适合作为无状态的服务组件共享使用。

BeanPostProcessor的作用:

// 在Bean初始化前后执行自定义逻辑 // AOP代理在此生成 public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) { return bean; // 初始化前处理 } @Override public Object postProcessAfterInitialization(Object bean, String beanName) { return bean; // 初始化后处理(AOP代理在此生成) } }
面试加分项:能说出Bean生命周期完整流程、BeanPostProcessor作用、Aware接口回调时机,说明你对Spring Bean机制有深入理解。

实战场景

场景:有状态Bean的线程安全问题

// 问题代码 @Service public class OrderService { private int orderCount; // 有状态,线程不安全 public void createOrder() { orderCount++; // 并发问题 } } // 解决方案1:使用局部变量 @Service public class OrderService { public void createOrder() { int orderCount = 0; // 局部变量 orderCount++; } } // 解决方案2:使用ThreadLocal @Service public class OrderService { private static final ThreadLocal orderCount = ThreadLocal.withInitial(() -> 0); public void createOrder() { orderCount.set(orderCount.get() + 1); } }

面试模拟

Q:Spring Bean的生命周期是怎样的?

A:四个阶段:1. 实例化(反射创建对象);2. 属性填充(依赖注入、Aware回调);3. 初始化(BeanPostProcessor → InitializingBean → init-method → BeanPostProcessor);4. 销毁(DisposableBean → destroy-method)。

Q:单例Bean是否线程安全?

A:Spring单例Bean本身不保证线程安全。无状态Bean(无成员变量)是安全的;有状态Bean(含可写成员变量)需要采取措施:局部变量、ThreadLocal、同步机制或改为Prototype作用域。