Bean初始化扩展点
在Spring的应用中,较多常见的会使用注解@PostConstruct用于对于进行一些Bean的初始化操作。但Spring中存在三种方法只可以进行初始化的指定,分别是
- 使用@PostConstruct
- 实现InitializingBean
- 使用@Bean(initMethod = “init”)
在populateBean的入口处,依次调下如下方法:
BeanPostProcessor#postProcessBeforeInitialization
首先会获取Bean的后置处理器并执行,其中存在一个CommonAnnotationBeanPostProcessor继承自InitDestroyAnnotationBeanPostProcessor;
从下面代码中看到其设置了初始化的注解参数为@PostConstruct
public CommonAnnotationBeanPostProcessor() {
setOrder(Ordered.LOWEST_PRECEDENCE - 3);
setInitAnnotationType(PostConstruct.class);
setDestroyAnnotationType(PreDestroy.class);
ignoreResourceType("javax.xml.ws.WebServiceContext");
}
查找初始化方法,根据配置的@PostConstruct注解,反射查找
private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
final boolean debug = logger.isDebugEnabled();
List<LifecycleElement> initMethods = new ArrayList<>();
List<LifecycleElement> destroyMethods = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<LifecycleElement> currInitMethods = new ArrayList<>();
final List<LifecycleElement> currDestroyMethods = new ArrayList<>();
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
LifecycleElement element = new LifecycleElement(method);
currInitMethods.add(element);
if (debug) {
logger.debug("Found init method on class [" + clazz.getName() + "]: " + method);
}
}
if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
currDestroyMethods.add(new LifecycleElement(method));
if (debug) {
logger.debug("Found destroy method on class [" + clazz.getName() + "]: " + method);
}
}
});
initMethods.addAll(0, currInitMethods);
destroyMethods.addAll(currDestroyMethods);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return new LifecycleMetadata(clazz, initMethods, destroyMethods);
}
在InitDestroyAnnotationBeanPostProcessor中的执行逻辑:
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;
}
InitializingBean#afterPropertiesSet
程序继续往下,invokeInitMethods(beanName, wrappedBean, mbd);这里的代码较为直接,boolean isInitializingBean = (bean instanceof InitializingBean);直接通过类型判断,执行回调的afterPropertiesSet方法。
接着查询Bean定义了initMethod配置的初始化方法,并调用执行。
invokeCustomInitMethod(beanName, bean, mbd);
BeanPostProcessor#postProcessAfterInitialization
见下
总结
扩展
知道上述原理后,考虑这样一个场景,设计一个注解用于控制Bean初始化最后一步额外操作。
这里要复用到BeanPostProcessor#postProcessAfterInitialization,可以看到其是初始化方法中最后一行代码,正好满足要求。
@Documented
@Retention(RUNTIME)
@Target(METHOD)
public @interface LastInit {
}
Bean后置处理器,继承InitDestroyAnnotationBeanPostProcessor,设置对应注解类即可,并在postProcessAfterInitialization中调用父类中的postProcessBeforeDestruction方法即可。
@Component
public class LastInitAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor {
public LastInitAnnotationBeanPostProcessor() {
super();
setInitAnnotationType(LastInit.class);
}
@Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
//不处理
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
super.postProcessBeforeInitialization(bean, beanName);
return bean;
}
}