乐趣区

关于java:initmethodpostcontructafterPropertiesSet的先后顺序

在牛客面经上遇到的一个面试题。忽然想尝试下
而后就开始做了

测试

        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        TestDao testDao = applicationContext.getBean(TestDao.class);
        ((ClassPathXmlApplicationContext) applicationContext).close();

测试的 bean

@Component
public class TestDao  implements InitializingBean, DisposableBean {public TestDao() {System.out.println("constructor");
    }

    @Async
    public void query(){System.out.println("Hello Spring!");
    }

    @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");
    }

    @Override
    public void destroy() throws Exception {System.out.println("destroy");
    }
    @PreDestroy
    public void PreDestroy(){System.out.println("PreDestroy");
    }
    public void destroyMethod(){System.out.println("destroyMethod");
    }
}

xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd

        http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>
    <bean id="testDao" class="com.test.dao.TestDao" init-method="InitMethod" destroy-method="destroyMethod"></bean>

</beans>

执行之后打印的后果

总的来说就是打印的后果是构造方法 -> 注解 @PostConstruct 办法 ->InitializingBean 接口的 afterPropertiesSet 办法 ->xml 中配置的 init-method 办法
同理销毁也是一样注解 @PreDestroy 办法 ->DisposableBean 接口的 destroy 办法 ->xml 中配置的 destroy-method 办法

源码

通过断点调试发现几个初始化办法都定位到了 AbstractAutowireCapableBeanFactory 的 initializeBean 办法中

protected Object initializeBean(final String beanName, final 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 注解的办法 InitDestroyAnnotationBeanPostProcessor#postProcessBeforeInitialization
            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;
    }

前面执行的两个办法
protected void invokeInitMethods(String beanName, final 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>) () -> {((InitializingBean) bean).afterPropertiesSet();
                    return null;
                }, getAccessControlContext());
            }
            catch (PrivilegedActionException pae) {throw pae.getException();
            }
        }
        else {
        // 执行 afterPropertiesSet 办法
            ((InitializingBean) bean).afterPropertiesSet();}
    }

    if (mbd != null && bean.getClass() != NullBean.class) {String initMethodName = mbd.getInitMethodName();
        if (StringUtils.hasLength(initMethodName) &&
                !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                !mbd.isExternallyManagedInitMethod(initMethodName)) {
                // 执行的是 xml 中自定义的 init-method 办法
            invokeCustomInitMethod(beanName, bean, mbd);
        }
    }
}

欢送搜寻关注自己与敌人共同开发的微信面经小程序【大厂面试助手】和公众号【微瞰技术】

退出移动版