基于 Spring Framework v5.2.6.RELEASE
概述
上一篇分析了 CommonAnnotationBeanPostProcessor 后处理器对标记了@
Resource
注解的属性和方法的解析以及注入处理。本篇来分析它对@PostConstruct
和@PreDestroy
注解的处理,这两部分内容共同构成了 Spring 对 JSR-250 的支持。
对这两个注解的处理逻辑,大部分都是在 CommonAnnotationBeanPostProcessor 的父类 InitDestroyAnnotationBeanPostProcessor 中完成的,本文主要涉及到了以下三个后处理方法:
postProcessMergedBeanDefinition
方法执行了对这两个注解所标记的方法的解析。postProcessBeforeInitialization
方法执行了对@PostConstruct
注解的处理。postProcessBeforeDestruction
方法执行了对@PreDestroy
注解的处理。
下面我们一一分析。
注解方法的解析
因为 Spring 注册到容器中的后处理器是 CommonAnnotationBeanPostProcessor,因此我们还是从它入手。首先看他的postProcessMergedBeanDefinition
方法。
// org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#postProcessMergedBeanDefinitionpublicvoidpostProcessMergedBeanDefinition(RootBeanDefinitionbeanDefinition, Class<?>beanType, StringbeanName) { super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName); InjectionMetadatametadata=findResourceMetadata(beanName, beanType, null); metadata.checkConfigMembers(beanDefinition); }
这个方法的后两行代码是用来解析@
Resource
注解相关内容的,上一篇中已经分析过了,我们只看第一行代码。这里调用了父类 InitDestroyAnnotationBeanPostProcessor 的同名方法,我们找到这个方法。
// org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor#postProcessMergedBeanDefinitionpublicvoidpostProcessMergedBeanDefinition(RootBeanDefinitionbeanDefinition, Class<?>beanType, StringbeanName) { LifecycleMetadatametadata=findLifecycleMetadata(beanType); metadata.checkConfigMembers(beanDefinition); }
这个方法在两个类中的实现很相似,不过用来处理的注解是不同的,我们还是按照代码执行的顺序来分析。
首先进入findLifecycleMetadata
方法。
findLifecycleMetadata 方法
// org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor#findLifecycleMetadataprivateLifecycleMetadatafindLifecycleMetadata(Class<?>clazz) { if (this.lifecycleMetadataCache==null) { // Happens after deserialization, during destruction...returnbuildLifecycleMetadata(clazz); } // Quick check on the concurrent map first, with minimal locking.LifecycleMetadatametadata=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); } returnmetadata; } } returnmetadata; }
这个方法是为了获取生命周期相关的元信息(LifecycleMetadata),其实就是当前 Bean 类型中标记了@PostConstruct
和@PreDestroy
注解的方法的元信息,首先会从lifecycleMetadataCache
缓存中获取,如果缓存为空,或者缓存中获取不到当前类型对应的元信息,则通过buildLifecycleMetadata
方法从类型信息中解析。
接下来,进入buildLifecycleMetadata
方法。
buildLifecycleMetadata 方法
// org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor#buildLifecycleMetadataprivateLifecycleMetadatabuildLifecycleMetadata(finalClass<?>clazz) { if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) { returnthis.emptyLifecycleMetadata; } List<LifecycleElement>initMethods=newArrayList<>(); List<LifecycleElement>destroyMethods=newArrayList<>(); Class<?>targetClass=clazz; do { finalList<LifecycleElement>currInitMethods=newArrayList<>(); finalList<LifecycleElement>currDestroyMethods=newArrayList<>(); ReflectionUtils.doWithLocalMethods(targetClass, method-> { if (this.initAnnotationType!=null&&method.isAnnotationPresent(this.initAnnotationType)) { LifecycleElementelement=newLifecycleElement(method); currInitMethods.add(element); if (logger.isTraceEnabled()) { logger.trace("Found init method on class ["+clazz.getName() +"]: "+method); } } if (this.destroyAnnotationType!=null&&method.isAnnotationPresent(this.destroyAnnotationType)) { currDestroyMethods.add(newLifecycleElement(method)); if (logger.isTraceEnabled()) { logger.trace("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 (initMethods.isEmpty() &&destroyMethods.isEmpty() ?this.emptyLifecycleMetadata : newLifecycleMetadata(clazz, initMethods, destroyMethods)); }
首先,会对当前的类型和注解进行校验,确保它们是需要进行解析和处理的类型。这里要处理的注解类型是this.initAnnotationType
和this.destroyAnnotationType
,这两个类型其实就是@PostConstruct
和@PreDestroy
注解。
然后,在do-while
循环中,会遍历clazz类型及其继承关系链上除了 Object 之外的所有类型,从这些类型的方法中,找到被标记了要处理的两个注解类型的方法,将他们的信息封装成对应的 LifecycleElement 对象,分别添加到initMethods
和destroyMethods
集合中。
最后,将当前的类型信息clazz
,与initMethods
和destroyMethods
集合一起封装为一个 LifecycleMetadata 对象作为结果返回。
至此,这些元信息就解析完了,我们再看postProcessMergedBeanDefinition
方法的第二行代码中的checkConfigMembers
方法。
LifecycleMetadata 的 checkConfigMembers 方法。
// org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata#checkConfigMemberspublicvoidcheckConfigMembers(RootBeanDefinitionbeanDefinition) { Set<LifecycleElement>checkedInitMethods=newLinkedHashSet<>(this.initMethods.size()); for (LifecycleElementelement : this.initMethods) { StringmethodIdentifier=element.getIdentifier(); if (!beanDefinition.isExternallyManagedInitMethod(methodIdentifier)) { beanDefinition.registerExternallyManagedInitMethod(methodIdentifier); checkedInitMethods.add(element); if (logger.isTraceEnabled()) { logger.trace("Registered init method on class ["+this.targetClass.getName() +"]: "+element); } } } Set<LifecycleElement>checkedDestroyMethods=newLinkedHashSet<>(this.destroyMethods.size()); for (LifecycleElementelement : this.destroyMethods) { StringmethodIdentifier=element.getIdentifier(); if (!beanDefinition.isExternallyManagedDestroyMethod(methodIdentifier)) { beanDefinition.registerExternallyManagedDestroyMethod(methodIdentifier); checkedDestroyMethods.add(element); if (logger.isTraceEnabled()) { logger.trace("Registered destroy method on class ["+this.targetClass.getName() +"]: "+element); } } } this.checkedInitMethods=checkedInitMethods; this.checkedDestroyMethods=checkedDestroyMethods; }
这个方法中,对元信息中的initMethods
和destroyMethods
两个集合分别做了处理。分别遍历两个集合中所有的方法信息,将没有被checkConfigMembers
方法处理过的所有方法进行标记并分别保存到checkedInitMethods
和checkedDestroyMethods
集合中。
这一步的目的,是为了避免同一个方法被多个同类型的后处理器执行多次。
至此,postProcessMergedBeanDefinition
方法的执行逻辑就结束了,它主要是完成了被@PostConstruct
和@PreDestroy
两个注解标记的方法元信息的解析。
接下来分别看看 Spring 是如何处理这些方法元信息的。
@PostConstruct 方法的处理
进入postProcessBeforeInitialization
方法,这个方法的实现在 InitDestroyAnnotationBeanPostProcessor 类中。
// org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor#postProcessBeforeInitializationpublicObjectpostProcessBeforeInitialization(Objectbean, StringbeanName) throwsBeansException { LifecycleMetadatametadata=findLifecycleMetadata(bean.getClass()); try { metadata.invokeInitMethods(bean, beanName); } catch (InvocationTargetExceptionex) { thrownewBeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException()); } catch (Throwableex) { thrownewBeanCreationException(beanName, "Failed to invoke init method", ex); } returnbean; }
这里的findLifecycleMetadata
方法前面已经介绍过了,只不过这次可以直接从缓存中获取到已经完成解析的元信息。
剩下的部分,关键的代码只有一句,就是调用metadata
的invokeInitMethods
方法。
后处理器的postProcessBeforeInitialization
方法是在 Bean 创建完成、执行初始化方法之前执行的,因此,这里也会执行 Bean 类型中定义的所有的被标记了@PostConstruct
注解的方法。
我们进入invokeInitMethods
方法。
// org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata#invokeInitMethodspublicvoidinvokeInitMethods(Objecttarget, StringbeanName) throwsThrowable { Collection<LifecycleElement>checkedInitMethods=this.checkedInitMethods; Collection<LifecycleElement>initMethodsToIterate= (checkedInitMethods!=null?checkedInitMethods : this.initMethods); if (!initMethodsToIterate.isEmpty()) { for (LifecycleElementelement : initMethodsToIterate) { if (logger.isTraceEnabled()) { logger.trace("Invoking init method on bean '"+beanName+"': "+element.getMethod()); } element.invoke(target); } } }
首先获取到当前元信息的checkedInitMethods
集合,如果它为空则获取initMethods
集合,赋值给initMethodsToIterate
变量,然后对其中的元素进行遍历。
这里面的每一个元素其实都是一个之前解析到的@PostConstruct
方法的元信息element
,这里会分别执行其invoke
方法。
进入invoke
方法。
// org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.LifecycleElement#invokepublicvoidinvoke(Objecttarget) throwsThrowable { ReflectionUtils.makeAccessible(this.method); this.method.invoke(target, (Object[]) null); }
很简单,就是通过反射机制执行这个方法。
至此,所有的@PostConstruct
方法就会在postProcessMergedBeanDefinition
后处理器方法被调用时执行一次。
下面看@PreDestroy
注解方法的处理。
@PreDestroy 方法的处理
进入postProcessBeforeDestruction
方法。
// org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor#postProcessBeforeDestructionpublicvoidpostProcessBeforeDestruction(Objectbean, StringbeanName) throwsBeansException { LifecycleMetadatametadata=findLifecycleMetadata(bean.getClass()); try { metadata.invokeDestroyMethods(bean, beanName); } catch (InvocationTargetExceptionex) { Stringmsg="Destroy method on bean with name '"+beanName+"' threw an exception"; if (logger.isDebugEnabled()) { logger.warn(msg, ex.getTargetException()); } else { logger.warn(msg+": "+ex.getTargetException()); } } catch (Throwableex) { logger.warn("Failed to invoke destroy method on bean with name '"+beanName+"'", ex); } }
可以看到,跟上一部分分析的postProcessBeforeInitialization
方法的执行逻辑是一样的,只不过这次处理的是元信息中checkedDestroyMethods
集合中的元素。也就是在一个 Bean 实例被晓慧钱,postProcessBeforeDestruction
方法被调用的时候,所有在 Bean 类型中定义的标记了@PreDestroy
注解的方法都会执行一遍。
总结
本文介绍了 InitDestroyAnnotationBeanPostProcessor 后处理器对@PostConstruct
和@PreDestroy
注解方法的解析和处理原理。
至此,CommonAnnotationBeanPostProcessor 后处理器相关的源码也全部分析完了。