Spring Bean 生命周期高阶用法:从回调到框架级扩展

Spring Bean 生命周期高阶用法:从回调到框架级扩展

把 Spring 容器当作一条「装配流水线」,在 7 个标准阶段之间任意「加戏」,即可零侵入地完成动态代理、多租户装配、优雅停机、第三方库接管等高级需求。


一、生命周期全景图(精简版)

阶段回调/扩展点典型用途
实例化前InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation跳过默认构造,返回代理
实例化后InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation决定是否继续属性填充
属性填充后BeanPostProcessor#postProcessProperties动态注入(如 @Value 解析增强)
初始化前BeanPostProcessor#postProcessBeforeInitialization日志、监控、AOP
初始化阶段@PostConstructInitializingBean#afterPropertiesSetinit-method业务初始化
初始化后BeanPostProcessor#postProcessAfterInitialization代理包装、缓存代理
销毁阶段@PreDestroyDisposableBean#destroydestroy-method资源释放
销毁前额外钩子DestructionAwareBeanPostProcessor#postProcessBeforeDestruction优雅停机、线程池关闭

二、6 个官方扩展点速查

接口/注解说明代码片段
InstantiationAwareBeanPostProcessor控制是否实例化/提前暴露代理见「实战 1」
SmartInstantiationAwareBeanPostProcessor解决循环依赖、选择构造器determineCandidateConstructors
BeanPostProcessor通用前置/后置处理与 Bean 实例一起注册
DestructionAwareBeanPostProcessor销毁前钩子关闭线程池、释放锁
InitializingBean / DisposableBean传统接口与容器深度集成
@PostConstruct / @PreDestroyJSR-250 注解零侵入

三、3 个高阶实战套路

1️⃣ 动态代理:在实例化阶段直接返回子类

public class RpcProxyCreator implements InstantiationAwareBeanPostProcessor {
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
        // 只对接口生成代理
        if (beanClass.isInterface() && beanClass.isAnnotationPresent(RpcClient.class)) {
            return Proxy.newProxyInstance(beanClass.getClassLoader(),
                                          new Class[]{beanClass},
                                          new RpcInvocationHandler());
        }
        return null; // 返回 null,继续默认流程
    }
}

效果:接口无需实现类,容器直接注入代理对象。

2️⃣ 多租户 Bean:实例化后动态注入租户字段

public class TenantBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        if (bean instanceof TenantAware) {
            ((TenantAware) bean).setTenantId(TenantContext.get());
        }
        return bean;
    }
}

效果:同一个 TenantService 在不同租户下拥有独立字段值。

3️⃣ 优雅停机:线程池安全关闭

public class ExecutorShutdownProcessor implements DestructionAwareBeanPostProcessor {
    @Override
    public void postProcessBeforeDestruction(Object bean, String beanName) {
        if (bean instanceof ExecutorService) {
            ExecutorService es = (ExecutorService) bean;
            es.shutdown();
            try { es.awaitTermination(5, TimeUnit.SECONDS); } 
            catch (InterruptedException ie) { es.shutdownNow(); }
        }
    }
}

效果:容器关闭时,所有线程池优雅终止,避免任务丢失。


四、组合模板:一条 Bean 同时享受所有钩子

@Component
public class MyBean implements InitializingBean, DisposableBean {
    @PostConstruct
    public void postConstruct() { /* 注解初始化 */ }

    @Override
    public void afterPropertiesSet() { /* 接口初始化 */ }

    @PreDestroy
    public void preDestroy() { /* 注解销毁 */ }

    @Override
    public void destroy() { /* 接口销毁 */ }
}

执行顺序(Spring 5.3+)

① postProcessBeforeInitialization
② @PostConstruct
③ afterPropertiesSet
④ postProcessAfterInitialization
⑤ 业务运行
⑥ @PreDestroy
⑦ destroy
⑧ postProcessBeforeDestruction

五、常见误区 & 对策

误区正解
在 Bean 内部直接 new Thread()ExecutorService 并注册销毁钩子
实现 InitializingBean 导致无法单元测试改用 @PostConstruct,更易 Mock
循环依赖无法解决实现 SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference

六、一句话总结

掌握 InstantiationAware、BeanPostProcessor、DestructionAware 三大接口,
就可以把 Spring Bean 生命周期变成「乐高流水线」:
实例化前换零件、初始化后加装饰、销毁前做清理——
高级玩法,不过如此。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

半部论语

如果觉得有帮助,打赏鼓励一下

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值