Spring中@PostConstruct的实现方法
作者:湘小宝666
前言
大多数java程序员都使用过@PostConstruct注解,它的作用就是在Bean初始化完成后执行,相当于我们常说的init()方法。但是我们看@PostConstruct只有单单的一个注解,它到底是如何实现在Bean初始化完成后就被调用的呢?
源码分析
我们通过idea搜索发现,只有CommonAnnotationBeanPostProcessor这个类使用了@PostConstruct:
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor implementsInstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {
public CommonAnnotationBeanPostProcessor() {
this.setOrder(2147483644);
// 给initAnnotationType赋值
this.setInitAnnotationType(PostConstruct.class);
this.setDestroyAnnotationType(PreDestroy.class);
this.ignoreResourceType("javax.xml.ws.WebServiceContext");
if (jndiPresent) {
this.jndiFactory = new SimpleJndiBeanFactory();
}
}
}通过源码发现,这显然就是一个BeanPostProcessor的子类啊,它在Spring的生命周期中起作用,所以我们可以重点关注postProcessBeforeInitialization()方法:
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 获取被@PostConstruct注解的方法元数据
InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata metadata = this.findLifecycleMetadata(bean.getClass());
try {
// 调用目标方法
metadata.invokeInitMethods(bean, beanName);
return bean;
} catch (InvocationTargetException var5) {
throw new BeanCreationException(beanName, "Invocation of init method failed", var5.getTargetException());
} catch (Throwable var6) {
throw new BeanCreationException(beanName, "Failed to invoke init method", var6);
}
}当Bean初始化完成后,postProcessBeforeInitialization()方法将被调用,所有被注解了@PostConstruct都会被调用,无论这个方法是在父类还是子类中:
private InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
// 如果缓存为null,那么构建缓存;这个缓存是存储Bean中所有被@PostConstruct注解的方法元数据
if (this.lifecycleMetadataCache == null) {
// 构建缓存
return this.buildLifecycleMetadata(clazz);
} else {
// 如果缓存不为null,那么从缓存中取出所有被@PostConstruct注解的方法元数据
InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata metadata =(InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata)this.lifecycleMetadataCache.get(clazz);
// 如果缓存中取出来的元数据为null,这段代码这种写法是考虑到现在有多个线程,用了加锁操作保证只有一个线程去构建缓存buildLifecycleMetadata()
if (metadata == null) {
synchronized(this.lifecycleMetadataCache) {
metadata = (InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata)this.lifecycleMetadataCache.get(clazz);
// 如果此时还没拿到元数据,就去构建缓存
if (metadata == null) {
// 收集好元数据
metadata = this.buildLifecycleMetadata(clazz);
// 构建缓存
this.lifecycleMetadataCache.put(clazz, metadata);
}
// 返回元数据
return metadata;
}
} else {
// 返回元数据
return metadata;
}
}
}1.缓存为null的情况下直接构建缓存;
2.缓存不为null,就从缓存中取被注解的方法元数据,没取到就构建缓存;
所以我们重点看看缓存是如何构建的:
private InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata buildLifecycleMetadata(Class<?> clazz) {
// 如果这个类一定没有被initAnnotationType或destroyAnnotationType注解
// 此时initAnnotationType就是我们的@PostConstruct注解
if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {
return this.emptyLifecycleMetadata;
} else {
// 准备好列表来装被注解的方法
List<InitDestroyAnnotationBeanPostProcessor.LifecycleElement> initMethods = new ArrayList();
List<InitDestroyAnnotationBeanPostProcessor.LifecycleElement> destroyMethods = new ArrayList();
Class targetClass = clazz;
// 准备循环向上遍历所有的父类
do {
List<InitDestroyAnnotationBeanPostProcessor.LifecycleElement> currInitMethods = new ArrayList();
List<InitDestroyAnnotationBeanPostProcessor.LifecycleElement> currDestroyMethods = new ArrayList();
ReflectionUtils.doWithLocalMethods(targetClass, (method) -> {
// 如果这个方法被@PostConstruct注解,那么就构建元数据并放进currInitMethods中
if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
InitDestroyAnnotationBeanPostProcessor.LifecycleElement element = newInitDestroyAnnotationBeanPostProcessor.LifecycleElement(method);
currInitMethods.add(element);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
}
}
// 下面是判断是否被destroyAnnotationType注解
if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
currDestroyMethods.add(new InitDestroyAnnotationBeanPostProcessor.LifecycleElement(method));
if (this.logger.isTraceEnabled()) {
this.logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);
}
}
});
// 先把当前类被注解的方法元数据列表放进initMethods头部
initMethods.addAll(0, currInitMethods);
destroyMethods.addAll(currDestroyMethods);
// 获取当前类的父类
targetClass = targetClass.getSuperclass();
// 准备遍历父类是否有被注解的方法,有的话收集好放进initMethods头部
} while(targetClass != null && targetClass != Object.class);
// 返回构建好的元数据
return initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata : newInitDestroyAnnotationBeanPostProcessor.LifecycleMetadata(clazz, initMethods, destroyMethods);
}
}所以我们通过上述源码的分析,最后得出以下结论:
1.
Bean的父类方法也可以使用@PostConstruct注解;2.执行的时候是先执行被
@PostConstruct注解的父类方法,再执行被@PostConstruct注解的子类方法;3.被
@PostConstruct注解的方法不能有任何参数,可以通过new InitDestroyAnnotationBeanPostProcessor.LifecycleElement(method)源码验证;
以上就是Spring中@PostConstruct的实现方法的详细内容,更多关于Spring @PostConstruct实现的资料请关注脚本之家其它相关文章!
