在《spring中BeanPostProcessor之二:CommonAnnotationBeanPostProcessor(01)》一文中,分析到在呼叫CommonAnnotationBeanPostProcessor類的postProcessMeredBeanDefinition方法時會先呼叫其父類的postProcessMeredBeanDefinition方法,下面就來分析CommonAnnotationBeanPostProcessor類的父類InitDestroyAnnoatationBeanPostProcessor。
一、概述
我們先看下CommonAnnotationAnnotationBeanPostProcessor類,上篇中介紹到該類有一個靜態程式碼塊會在類初始化的時候呼叫,在該類中還有一個預設的建構函式,
public CommonAnnotationBeanPostProcessor() { setOrder(Ordered.LOWEST_PRECEDENCE - 3); //@PostConstruct註解,作用在方法上 setInitAnnotationType(PostConstruct.class); //@PreDestroy註解,作用在方法上 setDestroyAnnotationType(PreDestroy.class); ignoreResourceType("javax.xml.ws.WebServiceContext"); }
該建構函式中分別呼叫了setInitAnnotationType和setDestroyAnnotationType方法,兩個方法分別呼叫其父類的方法,
/** * Specify the init annotation to check for, indicating initialization * methods to call after configuration of a bean. * <p>Any custom annotation can be used, since there are no required * annotation attributes. There is no default, although a typical choice * is the JSR-250 {@link javax.annotation.PostConstruct} annotation. */ public void setInitAnnotationType(Class<? extends Annotation> initAnnotationType) { this.initAnnotationType = initAnnotationType; } /** * Specify the destroy annotation to check for, indicating destruction * methods to call when the context is shutting down. * <p>Any custom annotation can be used, since there are no required * annotation attributes. There is no default, although a typical choice * is the JSR-250 {@link javax.annotation.PreDestroy} annotation. */ public void setDestroyAnnotationType(Class<? extends Annotation> destroyAnnotationType) { this.destroyAnnotationType = destroyAnnotationType; }
分別給的InitDestroyAnnotationBeanPostProcessor的initAnnotationType和destroyAnnotationType賦值@PostConstruct和@PreDestroy註解。
二、詳述
上面提到在呼叫CommonAnnotationBeanPostProcessor類的postProcessMeredBeanDefinition方法時會先呼叫父類的方法,下面看CommonAnnotationBeanPostProcessor的方法,
@Override public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) { super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName); InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null); metadata.checkConfigMembers(beanDefinition); }
上面是CommonAnnotationBeanPostProcessor的postProcessMergedBeanDefinition方法,可以看到呼叫了父類的postProcessMergedBeanDefinition方法,其他的方法在上篇部落格中已經分析,來重點分析InitDestroyAnnotationBeanPostProcessor的postProcessMergedBeanDefinition方法,
@Override public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) { LifecycleMetadata metadata = findLifecycleMetadata(beanType); metadata.checkConfigMembers(beanDefinition); }
在方法中呼叫了findLifecycleMetadata和checkConfigMembers方法,
private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) { //判斷lifecycleMetadataCache是否為空 if (this.lifecycleMetadataCache == null) { // Happens after deserialization, during destruction... return buildLifecycleMetadata(clazz); } // Quick check on the concurrent map first, with minimal locking. //從lifecycleMetadataCache中取,如果存在則直接返回,不存在則生成一個LifecycleMetadata物件並返回 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; }
在findLifecycleMetadata方法中主要呼叫的是buildLifecycleMetadata方法,改方法的返回值是LifecycleMetadata物件,之後把該物件放到lifecycleMetadataCache中,那麼這裡lifecycleMetadata應該是Map型別的,
@Nullable private final transient Map<Class<?>, LifecycleMetadata> lifecycleMetadataCache = new ConcurrentHashMap<>(256);
buildLifecycleMetadataf方法如下,
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<>(); //判斷方法上是否存在initAnnotationType的註解,這裡指的就是@PostConstruct註解 ReflectionUtils.doWithLocalMethods(targetClass, method -> { if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) { LifecycleElement element = new LifecycleElement(method); currInitMethods.add(element); if (logger.isTraceEnabled()) { logger.trace("Found init method on class [" + clazz.getName() + "]: " + method); } } //判斷方法上是否存在destroyAnnotationType的註解,這裡指的就是@PreDestroy註解 if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) { 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 = targetClass.getSuperclass(); } while (targetClass != null && targetClass != Object.class); return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata : new LifecycleMetadata(clazz, initMethods, destroyMethods)); }
從上面的分析,可以知道InitDestroyAnnotationBeanPostProcessor的postProcessMergedBeanDefinition方法完成的功能就是把類中含有@PostConstrunct和@PreDestroy註解的方法資訊快取到lifecycleMetadataCache中。也就是說在一個被spring管理的類中允許定義被這兩個註解修飾的方法,那方法有那些要求那,看上面的new LifecycleElement這裡,看LifecycleElement類
public LifecycleElement(Method method) { if (method.getParameterCount() != 0) { throw new IllegalStateException("Lifecycle method annotation requires a no-arg method: " + method); } this.method = method; this.identifier = (Modifier.isPrivate(method.getModifiers()) ? ClassUtils.getQualifiedMethodName(method) : method.getName()); }
看上面的異常,意思是不允許此類方法有方法引數,如果有引數則會拋異常。
三、使用場景
上面分析了InitDestroyAnnotationBeanPostProcessor類中postProcessMergedBeanDefinition方法的作用,就是把類中有@PostConstruct、@PreDestroy兩個註解的方法資訊進行快取,至於這兩個註解的作用及被這兩個註解標記的方法何時呼叫後面會繼續分析。
原創不易,有不正之處歡迎指正。