Spring的@PostConstruct和afterPropertiesSet和setBeanFactory和setApplicationContext和onApplicationEvent等顺序

   在 Spring 容器中,bean 的生命周期涉及多个回调方法的调用。以下是部分方法的调用顺序和它们之间的关系:

调用顺序

  1. setBeanFactory(BeanFactory beanFactory)

    当一个 bean 实现了 BeanFactoryAware 接口时,在属性注入完成后,Spring 会首先调用该方法,用于提供当前的 BeanFactory 实例。
  2. setApplicationContext(ApplicationContext applicationContext)

    如果一个 bean 实现了 ApplicationContextAware 接口,Spring 会在调用 setBeanFactory 后调用此方法,注入当前的应用上下文实例。
  3. afterPropertiesSet()

    这个方法来自于 InitializingBean 接口,Spring 在所有属性都被设置后(但在 @PostConstruct 方法调用之前)调用此方法,用于执行任何初始化逻辑。
  4. @PostConstruct

    如果 bean 中存在带有 @PostConstruct 注解的方法,Spring 将在调用 afterPropertiesSet() 方法后调用此方法。这个方法通常用于执行需要依赖于所有属性都已设置的初始化操作。
  5. postProcessAfterInitialization(...)

    如果 bean 实现了 BeanPostProcessor 接口,Spring 会在所有初始化操作包括 @PostConstruct 和 afterPropertiesSet())完成后调用此方法。通常用于对 bean 进行后处理。
  6. onApplicationEvent(...)

    如果一个 bean 实现了 ApplicationListener 接口,Spring 会在所有的 bean 初始化完成后触发事件。这是“事件处理”逻辑,不在 bean 的初始化顺序中。

总结调用顺序

简要顺序如下(这些都是在当前bean初始化且依赖注入完后调用):

  1. setBeanFactory(...)
  2. setApplicationContext(...)
  3. afterPropertiesSet()
  4. @PostConstruct
  5. postProcessAfterInitialization(...)
  6. onApplicationEvent(...)(在上下文初始化完成后触发)

示例

您可以通过实现多个接口并观察这些方法的调用顺序来理解它们的生命周期:

public class SpringTest implements BeanFactoryAware, ApplicationContextAware, BeanPostProcessor, InitializingBean, ApplicationListener<ApplicationEvent> {

    public SpringTest() throws InterruptedException {
        System.out.println("SpringTest constructor 1");
        TimeUnit.SECONDS.sleep(2);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        System.out.println("setBeanFactory called2");
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        System.out.println("setApplicationContext called3");
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    @PostConstruct
    public void init() throws InterruptedException {
        System.out.println("@PostConstruct called 4" );
        TimeUnit.SECONDS.sleep(2);
    }

    @Override
    public void afterPropertiesSet() throws InterruptedException {
        System.out.println("afterPropertiesSet called 5");
        TimeUnit.SECONDS.sleep(2);
    }
    @Override
    public  Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization called for 6-0(其他bean初始化时也会调用): " + beanName);
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("postProcessAfterInitialization called for 6-1(其他bean初始化时也会调用): " + beanName);
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return bean;
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println("onApplicationEvent called for 最后(在上下文初始化完成后触发): " + event);
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

结论

    理解这些生命周期回调的顺序对开发 Spring 应用至关重要,特别是在需要在不同阶段执行初始化逻辑时。良好的设计能够确保 bean 的正确初始化和依赖处理。

  • 11
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值