【Spring IOC】【七】容器源码解析- PostConstruct、PreDestory的源码分析
1 前言
@PostConstruct、@PreDestory这两个注解大家应该有用过吧,我们这篇分析一下主要是PostConstruct这个注解的解析时机和执行时机。
2 源码分析
2.1 解析时机-doCreateBean的applyMergedBeanDefinitionPostProcessors
首先是解析时机,就是我们的这个@PostConstruct注解是什么时候被分析的,CommonAnnotationBeanPostProcessor这个后置处理器还知道的吧,我们说过这个是在populateBean的时候会分析@Resource注解,这里它也会参与到@PostConstruct和@PreDestory,看他的初始化方法会将这两个注解,放入到集合中,它的父类是InitDestroyAnnotationBeanPostProcessor,那么两者有什么关联呢,分析源码如下:
这里是解析时机的入口,也就是doCreateBean方法这里会调用到InitDestroyAnnotationBeanPostProcessor的postProcessMergedBeanDefinition方法,来分析bean的postConstruct、preDestory,注意只是解析,并不会执行,解析并放进缓存中:
解析放进缓存中,并不会执行。
// 分析bean private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) { if (this.lifecycleMetadataCache == null) { // Happens after deserialization, during destruction... return buildLifecycleMetadata(clazz); } // Quick check on the concurrent map first, with minimal locking. LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz); if (metadata == null) { synchronized (this.lifecycleMetadataCache) { metadata = this.lifecycleMetadataCache.get(clazz); if (metadata == null) { metadata = buildLifecycleMetadata(clazz); // 放进缓存中 this.lifecycleMetadataCache.put(clazz, metadata); } return metadata; } } return metadata; }// 返回LifecycleMetadata对象
private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) { // this.initAnnotationType 里边有PostConstruct注解 // this.destroyAnnotationType 里边有PreDestory注解 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 -> { // 判断方法是由有PostConstruct注解 if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) { LifecycleElement element = new LifecycleElement(method); // 有的话就添加进currInitMethods里 currInitMethods.add(element); // 判断方法是由有PreDestory注解 if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) { // 有的话就添加进currDestroyMethods里 currDestroyMethods.add(new LifecycleElement(method)); initMethods.addAll(0, currInitMethods); destroyMethods.addAll(currDestroyMethods); targetClass = targetClass.getSuperclass();
} while (targetClass != null && targetClass != Object.class); return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata : new LifecycleMetadata(clazz, initMethods, destroyMethods)); }
解析时机大概的流程如下:
- doCreateBean为入口调用applyMergedBeanDefinitionPostProcessors
- InitDestroyAnnotationBeanPostProcessor的postProcessMergedBeanDefinition执行进行bean的解析返回
- 解析完得到LifecycleMetadata并缓存到lifecycleMetadataCache
2.2 执行时机-initializeBean中执行前置处理applyBeanPostProcessorsBeforeInitialization
@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; }
public void invokeInitMethods(Object target, String beanName) throws Throwable { Collection<LifecycleElement> checkedInitMethods = this.checkedInitMethods; Collection<LifecycleElement> initMethodsToIterate = (checkedInitMethods != null ? checkedInitMethods : this.initMethods); if (!initMethodsToIterate.isEmpty()) { for (LifecycleElement element : initMethodsToIterate) { if (logger.isTraceEnabled()) { logger.trace("Invoking init method on bean '" + beanName + "': " + element.getMethod()); } // 反射执行 element.invoke(target); } } }
3 小结
哦的肯不,一个字巧妙,有哪里理解不对的,还望指正奥,加油。