上一篇中,我们了解了@Autowire注解的底层原理,Spring会通过Bean的后处理器AutowiredAnnotationBeanPostProcessor,解析bean实例中的字段和方法上的注解@Autowired,最后会将对应的注解信息注入到属性或者方法参数上。今天我们看下另外的两个注解@PostConstruct和@PreDestroy。
我们要分析注解@PostConstruct和注解@PreDestory的底层源码,我们得要先找到源码的入口在哪,那Spring到底是在什么时候解析这两个注解的呢?和之前一样,我们先到这两个注解类中先看下:
在这两个注解中,我们没有找到相关的信息。那会不会和解析注解@Autowired的方式类似,毕竟注解@PostConstruct和注解@PreDestory有一点是和注解@Autowired类似的,也就是注解是可以添加在方法上的,而前面我们分析注解@Autowired的底层源码时,发现最终是通过Bean的工厂后处理器来处理的。那在什么地方会用到这两个注解呢?就是在bean实例初始化的时候,我们可以来看下:
我们发现方法applyBeanPostProcessorsBeforeInitialization和方法applyBeanPostProcessorsAfterInitialization,通过前面的分析我们也知道,这两个方法分别是在执行BeanPostProcessor中的前置和后置处理方法。我们可以先到方法applyBeanPostProcessorsBeforeInitialization中看下:
可以看到,这里会执行Bean后处理器中的前置处理方法,我们可以看下这个里面有哪些Bean的后处理器:
可以看到这里的后处理器还是挺多的,不过从这个名称上来看,后处理器中InitDestroyAnnotationBeanPostProcessor应该和我们本次的两个注解有关,通过名称我们可以知道,这个Bean的后处理器,应该可以同时处理初始化方法和销毁方法相关的注解信息。我们可以到InitDestroyAnnotationBeanPostProcessor类中看下:
可以看到,InitDestroyAnnotationBeanPostProcessor类中的前置和后置处理方法中,只有前置处理方法postProcessBeforeInitialization是有具体的逻辑实现的。在方法postProcessBeforeInitialization中,我们可以看到通过metadata调用方法invokeInitMethods,很明显方法invokeInitMethods就是在执行初始化相关的方法,这也符合我们前面看到的先执行初始化方法的逻辑,初始化方法的确应也该在这里被执行。我们可以断定Bean后处理器InitDestroyAnnotationBeanPostProcessor,就是用来处理注解@PostConstruct和注解@PreDestory的。们回到方法postProcessBeforeInitialization中看下:
我们到方法findLifecycleMetadata中看下:
可以看到,方法findLifecycleMetadata的结构,首先是去缓存中获取注解的信息,如果没有的话就要重新去解析了。这里面最关键的方法还是buildLifecycleMetadata方法,我们跟进去看下:
private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
// 看下当前类是否符合候选的类型
if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {
return this.emptyLifecycleMetadata;
}
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 -> {
// 方法method中是否存在注解this.initAnnotationType 类型,也就是 注解@PostConstruct
if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
// 将方法封装到 LifecycleElement 中,最后添加到集合 currInitMethods
LifecycleElement element = new LifecycleElement(method);
currInitMethods.add(element);
if (logger.isTraceEnabled()) {
logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
}
}
// 方法method 中是否存在注解 this.destroyAnnotationType 也就是注解 @PreDestroy
if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
// 将方法封装到 lifecycleElement 中, 最后添加到集合 currDestroyMethods
currDestroyMethods.add(new LifecycleElement(method));
if (logger.isTraceEnabled()) {
logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);
}
}
});
initMethods.addAll(0, currInitMethods);
destroyMethods.addAll(currDestroyMethods);
// 对 targetClass的父类, 在下一轮 while 循环进行同样的解析处理
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
// 最后 ,如何初始化 或 销毁方法相应的注解存在, 最终会封装到组件 LifecycleMetadata 中
return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata :
new LifecycleMetadata(clazz, initMethods, destroyMethods));
}
方法findLifecycleMetadata一开始先调用AnnotationUtils类中的方法isCandidateClass,判断下当前的类是否符合候选条件。就是有没有注解 @PostConstruct 和 注解 @PreDestroy。如果添加了这两个注解,就将方法method封装到LifecycleElement中,然后分别添加到集合currInitMethods和currDestroyMethods中。我们可以看下,在LifecycleElement的构造方法中会如何处理:
我们再看下剩下的一些逻辑:
可以看到,接下来会将targetClass的父类赋值给targetClass,也就是说接下来在下一轮while循环中,会解析当前类的父类中的注解,最后将解析到的所有信息封装到组件LifecycleMetadata中并返回。我们看下 LifecycleMetadata的构造方法中看一下:
将注解@PostConstruct对应的元数据信息,赋值给成员变量this.initMethods,而注解@PreDestory对应的元数据信息,则赋值给成员变量this.destroyMethods,我们再回到方法postProcessBeforeInitialization:
我们再到方法invokeInitMethods中看下:
在方法invokeInitMethods其实就是在遍历注解@PostConstruct相关的信息了,我们可以到element的invoke方法中看下:
底层其实就是在执行注解@PostConstruct对应的方法,而且是通过反射执行的。
而我们执行@PreDestroy对应的销毁方法在哪里呢?大家还记得bean在实例化最后面,还注册了一个实现了DisposableBean 接口的实现类DisposableBeanAdapter我们可以再到它的destroy方法中看下:
我们通过在这个Destroy 方法中,执行了Bean的后处理器。Bean后处理器InitDestroyAnnotationBeanPostProcessor,它同样也是接口DestructionAwareBeanPostProcessor的实现类。我们可以到InitDestroyAnnotationBeanPostProcessor中的方法postProcessBeforeDestruction看下:
这里又重新调用方法findLifecycleMetadata,到bean的类中解析注解@PostConstruct和注解@PreDestory的元数据信息,然后再调用方法invokeDestroyMethods执行注解@PreDestory对应的销毁方法。总的来说从执行顺序上,注解指定的方法都是先执行的,接着执行如接口InitializingBean和接口DisposableBean中指定的方法,最后才执行属性init-method和属性destroy-method指定的方法。