一句话总结
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作用域。