@PostConstruct、init-method和afterPropertiesSet执行顺序

 作者简介:大家好,我是码炫码哥,前中兴通讯、美团架构师,现任某互联网公司CTO,兼职码炫课堂主讲源码系列专题


代表作:《jdk源码&多线程&高并发》,《深入tomcat源码解析》,《深入netty源码解析》,《深入dubbo源码解析》,《深入springboot源码解析》,《深入spring源码解析》,《深入redis源码解析》等


联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬。码炫课堂的个人空间-码炫码哥个人主页-面试,源码等

回答

在 Spring 中,@PostConstructinit-method 和 afterPropertiesSet 都是用于在 Bean 初始化阶段执行自定义初始化逻辑的方法。他们的执行顺序如下:

  • @PostConstruct:首先是 @PostConstruct 执行。@PostConstruct 属于 JSR-250 标准注解,为 Java EE 标准中的注解。Spring 管理 Bean 的生命周期时会自动识别 @PostConstruct,并在属性注入完成之后执行。所以,@PostConstruct 执行时机比其他 Spring 专有的初始化方法更早。
  • afterPropertiesSet:是 Spring 专门为 Bean 的初始化设计的一个方法,定义在 InitializingBean 接口中,用来定义一些初始化逻辑。Spring 在创建 Bean 的过程中会检查 Bean 是否实现了 InitializingBean 接口,如果实现了则在 @PostConstruct 方法执行完毕后调用 afterPropertiesSet 方法。
  • init-method:在 Spring 配置文件(如 XML 配置)或者 @Bean 注解中指定的方法,该方法会在前两个初始化步骤执行完毕后调用。

所以,三者的执行顺序为:@PostConstruct > InitializingBean > init-method

详解

使用一个例子来看看:

public class BeanInitTest implements InitializingBean {
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet 执行");
    }

    @PostConstruct
    public void postConstructMethod() {
        System.out.println("@PostConstruct 执行");
    }

    public void initMethod(){
        System.out.println("init-method 执行");
    }

    @Configuration
    static class InitConfiguration {
        @Bean(initMethod = "initMethod")
        public BeanInitTest getInitMethodBean() {
            return new BeanInitTest();
        }
    }
}

然后启动下应用程序,查看执行结果:

我们再从源码层次来看,通过 debug 的跟踪,可以发现这几个初始化的方法都是在 AbstractAutowireCapableBeanFactory#initializeBean() 中:

  protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    if (System.getSecurityManager() != null) {
      AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
        invokeAwareMethods(beanName, bean);
        return null;
      }, getAccessControlContext());
    }
    else {
      invokeAwareMethods(beanName, bean);
    }

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
      // 这里是执行 @PostConstruct 的方法
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
      // 这里执行的是 afterPropertiesSet 和 init-method 方法 
      invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
      throw new BeanCreationException(
          (mbd != null ? mbd.getResourceDescription() : null),
          beanName, "Invocation of init method failed", ex);
    }
    if (mbd == null || !mbd.isSynthetic()) {
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
  }

从这个方法可以看出,先执行 @PostConstruct 的方法,然后调用 invokeInitMethods() 执行afterPropertiesSet 和 init-method

  protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
      throws Throwable {

    boolean isInitializingBean = (bean instanceof InitializingBean);
    if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
      if (logger.isTraceEnabled()) {
        logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
      }
      if (System.getSecurityManager() != null) {
        try {
          AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
            // 执行 afterPropertiesSet
            ((InitializingBean) bean).afterPropertiesSet();
            return null;
          }, getAccessControlContext());
        }
        catch (PrivilegedActionException pae) {
          throw pae.getException();
        }
      }
      else {
          // 执行 afterPropertiesSet
        ((InitializingBean) bean).afterPropertiesSet();
      }
    }

    if (mbd != null && bean.getClass() != NullBean.class) {
      // 执行 init-method 
      String initMethodName = mbd.getInitMethodName();
      if (StringUtils.hasLength(initMethodName) &&
          !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
          !mbd.isExternallyManagedInitMethod(initMethodName)) {
        invokeCustomInitMethod(beanName, bean, mbd);
      }
    }
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值