作者简介:大家好,我是码炫码哥,前中兴通讯、美团架构师,现任某互联网公司CTO,兼职码炫课堂主讲源码系列专题
代表作:《jdk源码&多线程&高并发》,《深入tomcat源码解析》,《深入netty源码解析》,《深入dubbo源码解析》,《深入springboot源码解析》,《深入spring源码解析》,《深入redis源码解析》等
联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬。码炫课堂的个人空间-码炫码哥个人主页-面试,源码等
回答
在 Spring 中,@PostConstruct
、init-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);
}
}
}