在开发过程中,在某些情况,需要对一个bean做一些初始化的,但是在未采取构造注入的情况下,执行构造函数时,该对象的属性都还没有通过自动装配注入,因此,一般对于bean的初始化工作是无法放入到构造函数的。于是经常会使用@PostConstruct和继承InitializingBean的afterPropertiesSet做初始化,那么这两种方式有什么异同呢?
执行时机
...................
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
..................
知道Bean创建过程的都知道populateBean之后,意味着该bean的属性已经注入完毕。
关键方法
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
//先执行invokeAwareMethods,通过XXAware接口注入bean需要的属性
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()) {
//执行BeanPostProcessor方法的前置方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
//执行Bean的初始化方法
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()) {
//执行BeanPostProcessor方法的后置方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
@PostConstract执行实际
通过断点发现@PostConstruct方法是通过CommonAnnotationBeanPostProcessor的前置方法执行的
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
metadata.invokeInitMethods(bean, beanName);
}
catch (InvocationTargetException ex) {
throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
afterPropertiesSet执行
通过上面关键方法initializeBean中的invokeInitMethods执行
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
······················
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("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)) {
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
通过省略的代码来看invokeInitMethods会执行InitializingBean的afterPropertiesSet方法,并且执行用户自定义在Beandifination中的初始化方法
总结
相同点:@PostConstruct和afterPropertiesSet都是在bean的属性注入完毕之后才执行,都可以用来进行bean 的初始化
区别:@PostConstruct是通过BeanPostProcessor的前置方法中执行的(我们也可以参考这个自定义注解实现),略早于通过继承InitializingBean的afterPropertiesSet初始化方法。