分析构造器、init-method、@PostConstruct、afterPropertiesSet谁先谁后

构造器、init-method、@PostConstruct、afterPropertiesSet 都可以做初始化用,但到底执行顺序是怎么样的呢?(调式Spring版本为4.3.12.RELEASE)

示例

先写个例子,看一下效果

TestInit.java
public class TestInit implements InitializingBean {
    public TestInit() {
        System.out.println("constructor");
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet");
    }
    @PostConstruct
    public void postConstruct(){
        System.out.println("postConstruct");
    }
    public void initMethod() {
        System.out.println("initMethod");
    }   
}
InitDemo.java
@Component
public class InitClass {
    @Bean(initMethod = "initMethod")
    public TestInit initTest(){
        return new TestInit();
    }
}

执行结果:

constructor
postConstruct
afterPropertiesSet
initMethod

可以看到执行顺序为 constructor > postConstruct > afterPropertiesSet > initMethod

源码分析

  1. 构造器,是属于java类的,在实例化的时候就会被调用,所以毋庸置疑

  2. postConstruct > afterPropertiesSet > initMethod 这三个顺序是如何决定的?
    我们分别在TestInit.java 对应的3个方法体中打一个断点,跑起来
    断点首先到了postConstruct中,看下调用栈

    73ebc03ec9b1fb5ec59d6ef033f7e321c2e.jpg


    往下走,跳过该断点,到了afterPropertiesSet中,调用栈是这样的

    bc8a82bcc604f1342b60a161a450e175e5e.jpg


    继续往下走,跳过该断点,到了initMethod中,同样看调用栈

    2ab25dd3859838bd974ceb5c0d5a2b059b9.jpg


    有没有发现,都是从initializeBean开始的,看下这个地方的代码

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
       //是否启用了安全管理器
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged(new PrivilegedAction<Object>() {
                @Override
                public Object run() {
                    invokeAwareMethods(beanName, bean);
                    return null;
                }
            }, getAccessControlContext());
        }
        else {
            //执行aware扩展点
            invokeAwareMethods(beanName, bean);
        }

        Object wrappedBean = bean;
        //Synthetic是由编译器生成的类型
        if (mbd == null || !mbd.isSynthetic()) {
//如果实现了BeanPostProcessor接口 这里会执行postProcessBeforeInitialization方法
//@PostConstruct注解是在CommonAnnotationBeanPostProcessor类中初始化的
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }

        try {
            //这里就开始执行initMethod 和 afterPropertiesSet方法
            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方法中

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

        boolean isInitializingBean = (bean instanceof InitializingBean);
        if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
            if (logger.isDebugEnabled()) {
                logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
            }
            if (System.getSecurityManager() != null) {
                try {
                    AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                        @Override
                        public Object run() throws Exception {
                            ((InitializingBean) bean).afterPropertiesSet();
                            return null;
                        }
                    }, getAccessControlContext());
                }
                catch (PrivilegedActionException pae) {
                    throw pae.getException();
                }
            }
            else {
                ((InitializingBean) bean).afterPropertiesSet();
            }
        }

        if (mbd != null) {
            String initMethodName = mbd.getInitMethodName();
            if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                    !mbd.isExternallyManagedInitMethod(initMethodName)) {
                invokeCustomInitMethod(beanName, bean, mbd);
            }
        }
    }

在这个方法里,一目了然就能看出来afterPropertiesSet先执行,最后执行了initMethod

结果

执行顺序为 constructor > postConstruct > afterPropertiesSet > initMethod

640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1

转载于:https://my.oschina.net/itsaysay/blog/3011833

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值