Spring Bean 生命周期,看完就忘不了

0 阅读2分钟

面试被问"Spring Bean 的生命周期",背了一堆名词(实例化、属性注入、初始化、销毁),但面试官追问"具体在哪个方法里触发的"就卡壳了。

完整流程

1. 实例化(Instantiation)
   ↓ 调用构造函数创建对象
2. 属性注入(Populate)
   ↓ @Autowired、@Value 注入依赖
3. Aware 接口回调
   ↓ BeanNameAware、BeanFactoryAware、ApplicationContextAware
4. BeanPostProcessor 前置处理
   ↓ postProcessBeforeInitialization()
5. 初始化(Initialization)
   ↓ @PostConstruct → InitializingBean.afterPropertiesSet() → init-method
6. BeanPostProcessor 后置处理
   ↓ postProcessAfterInitialization()  ← AOP 代理在这里创建
7. 使用中
   ↓ Bean 在容器里被使用
8. 销毁(Destruction)
   ↓ @PreDestroy → DisposableBean.destroy() → destroy-method

用代码验证

@Component
public class MyBean implements InitializingBean, DisposableBean,
        BeanNameAware, ApplicationContextAware {

    public MyBean() {
        System.out.println("1. 构造函数(实例化)");
    }

    @Value("${app.name:default}")
    private String appName;

    @Autowired
    private SomeDependency dep;
    // ↑ 2. 属性注入(在构造函数之后)

    @Override
    public void setBeanName(String name) {
        System.out.println("3a. BeanNameAware: " + name);
    }

    @Override
    public void setApplicationContext(ApplicationContext ctx) {
        System.out.println("3b. ApplicationContextAware");
    }

    @PostConstruct
    public void postConstruct() {
        System.out.println("5a. @PostConstruct");
    }

    @Override
    public void afterPropertiesSet() {
        System.out.println("5b. InitializingBean.afterPropertiesSet");
    }

    public void customInit() {
        System.out.println("5c. init-method");
    }

    @PreDestroy
    public void preDestroy() {
        System.out.println("8a. @PreDestroy");
    }

    @Override
    public void destroy() {
        System.out.println("8b. DisposableBean.destroy");
    }

    public void customDestroy() {
        System.out.println("8c. destroy-method");
    }
}

启动后输出:

1. 构造函数(实例化)
3a. BeanNameAware: myBean
3b. ApplicationContextAware
5a. @PostConstruct
5b. InitializingBean.afterPropertiesSet
5c. init-method

关闭容器时:

8a. @PreDestroy
8b. DisposableBean.destroy
8c. destroy-method

实际开发中最常用的

大部分场景只需要关注三个注解:

@Component
public class CacheManager {

    private Cache cache;

    // 构造函数注入依赖
    public CacheManager(RedisTemplate<String, String> redisTemplate) {
        this.cache = new Cache(redisTemplate);
    }

    @PostConstruct  // 初始化:Bean 创建完、属性注入完后执行
    public void init() {
        cache.warmUp();  // 预热缓存
        System.out.println("缓存管理器初始化完成");
    }

    @PreDestroy   // 销毁:容器关闭前执行
    public void cleanup() {
        cache.flush();  // 刷盘
        System.out.println("缓存管理器已清理");
    }
}

@PostConstruct 和 @PreDestroy 覆盖了 90% 的场景。

BeanPostProcessor — AOP 的秘密

@Component
public class TimingBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String name) {
        // 初始化之前处理
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String name) {
        // 初始化之后处理
        // AOP 代理就是在这里创建的!
        if (bean.getClass().isAnnotationPresent(Timed.class)) {
            return createProxy(bean);  // 返回代理对象替换原对象
        }
        return bean;
    }
}

postProcessAfterInitialization 可以返回一个代理对象替换原来的 Bean。Spring AOP 就是这么干的——在初始化后把原 Bean 包一层代理。

作用域对生命周期的影响

Scope生命周期
singleton(默认)容器启动时创建,容器关闭时销毁
prototype每次注入时创建,容器不管销毁
request每个 HTTP 请求创建一个
session每个 Session 创建一个

prototype 的 Bean 容器不负责销毁——创建完就交给调用方了,需要自己清理。

总结

Bean 生命周期:构造函数 → 属性注入 → Aware 回调 → 前置处理 → 初始化(@PostConstruct → afterPropertiesSet → init-method)→ 后置处理(AOP 在这里)→ 使用 → 销毁(@PreDestroy → destroy → destroy-method)。实际开发中记住 @PostConstruct 和 @PreDestroy 就够了,面试的时候把完整流程说一遍。