From 3b9605bc57f5d456be4471cac5e7073fe3657a79 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 19 Nov 2009 23:49:10 +0000 Subject: [PATCH] init/destroy methods get processed in the order of declaration at each hierarchy level (SPR-6344); process DestructionAwareBeanPostProcessors in common post-processor order; aligned metadata retrieval code --- .../AutowiredAnnotationBeanPostProcessor.java | 92 +++++++------- ...nitDestroyAnnotationBeanPostProcessor.java | 113 ++++++++++-------- .../support/DisposableBeanAdapter.java | 4 +- 3 files changed, 114 insertions(+), 95 deletions(-) diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java index 2ebd6ed1c8f..78538586930 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java @@ -303,56 +303,14 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean } - private InjectionMetadata findAutowiringMetadata(final Class clazz) { + private InjectionMetadata findAutowiringMetadata(Class clazz) { // Quick check on the concurrent map first, with minimal locking. InjectionMetadata metadata = this.injectionMetadataCache.get(clazz); if (metadata == null) { synchronized (this.injectionMetadataCache) { metadata = this.injectionMetadataCache.get(clazz); if (metadata == null) { - LinkedList elements = new LinkedList(); - Class targetClass = clazz; - - do { - LinkedList currElements = new LinkedList(); - for (Field field : targetClass.getDeclaredFields()) { - Annotation annotation = findAutowiredAnnotation(field); - if (annotation != null) { - if (Modifier.isStatic(field.getModifiers())) { - if (logger.isWarnEnabled()) { - logger.warn("Autowired annotation is not supported on static fields: " + field); - } - continue; - } - boolean required = determineRequiredStatus(annotation); - currElements.add(new AutowiredFieldElement(field, required)); - } - } - for (Method method : targetClass.getDeclaredMethods()) { - Annotation annotation = findAutowiredAnnotation(method); - if (annotation != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) { - if (Modifier.isStatic(method.getModifiers())) { - if (logger.isWarnEnabled()) { - logger.warn("Autowired annotation is not supported on static methods: " + method); - } - continue; - } - if (method.getParameterTypes().length == 0) { - if (logger.isWarnEnabled()) { - logger.warn("Autowired annotation should be used on methods with actual parameters: " + method); - } - } - boolean required = determineRequiredStatus(annotation); - PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method); - currElements.add(new AutowiredMethodElement(method, required, pd)); - } - } - elements.addAll(0, currElements); - targetClass = targetClass.getSuperclass(); - } - while (targetClass != null && targetClass != Object.class); - - metadata = new InjectionMetadata(clazz, elements); + metadata = buildAutowiringMetadata(clazz); this.injectionMetadataCache.put(clazz, metadata); } } @@ -360,6 +318,52 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean return metadata; } + private InjectionMetadata buildAutowiringMetadata(Class clazz) { + LinkedList elements = new LinkedList(); + Class targetClass = clazz; + + do { + LinkedList currElements = new LinkedList(); + for (Field field : targetClass.getDeclaredFields()) { + Annotation annotation = findAutowiredAnnotation(field); + if (annotation != null) { + if (Modifier.isStatic(field.getModifiers())) { + if (logger.isWarnEnabled()) { + logger.warn("Autowired annotation is not supported on static fields: " + field); + } + continue; + } + boolean required = determineRequiredStatus(annotation); + currElements.add(new AutowiredFieldElement(field, required)); + } + } + for (Method method : targetClass.getDeclaredMethods()) { + Annotation annotation = findAutowiredAnnotation(method); + if (annotation != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) { + if (Modifier.isStatic(method.getModifiers())) { + if (logger.isWarnEnabled()) { + logger.warn("Autowired annotation is not supported on static methods: " + method); + } + continue; + } + if (method.getParameterTypes().length == 0) { + if (logger.isWarnEnabled()) { + logger.warn("Autowired annotation should be used on methods with actual parameters: " + method); + } + } + boolean required = determineRequiredStatus(annotation); + PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method); + currElements.add(new AutowiredMethodElement(method, required, pd)); + } + } + elements.addAll(0, currElements); + targetClass = targetClass.getSuperclass(); + } + while (targetClass != null && targetClass != Object.class); + + return new InjectionMetadata(clazz, elements); + } + private Annotation findAutowiredAnnotation(AccessibleObject ao) { for (Class type : this.autowiredAnnotationTypes) { Annotation annotation = ao.getAnnotation(type); diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/annotation/InitDestroyAnnotationBeanPostProcessor.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/annotation/InitDestroyAnnotationBeanPostProcessor.java index b8adac7e687..eaf270f8131 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/annotation/InitDestroyAnnotationBeanPostProcessor.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/annotation/InitDestroyAnnotationBeanPostProcessor.java @@ -25,8 +25,10 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Collection; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.logging.Log; @@ -118,24 +120,7 @@ public class InitDestroyAnnotationBeanPostProcessor public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName) { if (beanType != null) { LifecycleMetadata metadata = findLifecycleMetadata(beanType); - for (Iterator it = metadata.getInitMethods().iterator(); it.hasNext();) { - String methodIdentifier = it.next().getIdentifier(); - if (!beanDefinition.isExternallyManagedInitMethod(methodIdentifier)) { - beanDefinition.registerExternallyManagedInitMethod(methodIdentifier); - } - else { - it.remove(); - } - } - for (Iterator it = metadata.getDestroyMethods().iterator(); it.hasNext();) { - String methodIdentifier = it.next().getIdentifier(); - if (!beanDefinition.isExternallyManagedDestroyMethod(methodIdentifier)) { - beanDefinition.registerExternallyManagedDestroyMethod(methodIdentifier); - } - else { - it.remove(); - } - } + metadata.checkConfigMembers(beanDefinition); } } @@ -197,30 +182,41 @@ public class InitDestroyAnnotationBeanPostProcessor return metadata; } - private LifecycleMetadata buildLifecycleMetadata(final Class clazz) { - final LifecycleMetadata newMetadata = new LifecycleMetadata(); + private LifecycleMetadata buildLifecycleMetadata(Class clazz) { final boolean debug = logger.isDebugEnabled(); - ReflectionUtils.doWithMethods(clazz, new ReflectionUtils.MethodCallback() { - public void doWith(Method method) { - if (initAnnotationType != null) { - if (method.getAnnotation(initAnnotationType) != null) { - newMetadata.addInitMethod(method); + LinkedList initMethods = new LinkedList(); + LinkedList destroyMethods = new LinkedList(); + Class targetClass = clazz; + + do { + LinkedList currInitMethods = new LinkedList(); + LinkedList currDestroyMethods = new LinkedList(); + for (Method method : targetClass.getDeclaredMethods()) { + if (this.initAnnotationType != null) { + if (method.getAnnotation(this.initAnnotationType) != null) { + LifecycleElement element = new LifecycleElement(method); + currInitMethods.add(element); if (debug) { logger.debug("Found init method on class [" + clazz.getName() + "]: " + method); } } } - if (destroyAnnotationType != null) { - if (method.getAnnotation(destroyAnnotationType) != null) { - newMetadata.addDestroyMethod(method); + if (this.destroyAnnotationType != null) { + if (method.getAnnotation(this.destroyAnnotationType) != null) { + currDestroyMethods.add(new LifecycleElement(method)); if (debug) { logger.debug("Found destroy method on class [" + clazz.getName() + "]: " + method); } } } } - }); - return newMetadata; + initMethods.addAll(0, currInitMethods); + destroyMethods.addAll(currDestroyMethods); + targetClass = targetClass.getSuperclass(); + } + while (targetClass != null && targetClass != Object.class); + + return new LifecycleMetadata(clazz, initMethods, destroyMethods); } @@ -242,19 +238,49 @@ public class InitDestroyAnnotationBeanPostProcessor */ private class LifecycleMetadata { - private final LinkedList initMethods = new LinkedList(); + private final Set initMethods; - private final LinkedList destroyMethods = new LinkedList(); + private final Set destroyMethods; - public void addInitMethod(Method method) { - LifecycleElement element = new LifecycleElement(method); - if (!this.initMethods.contains(element)) { - this.initMethods.addFirst(element); + public LifecycleMetadata(Class targetClass, Collection initMethods, + Collection destroyMethods) { + + this.initMethods = new LinkedHashSet(); + for (LifecycleElement element : initMethods) { + if (logger.isDebugEnabled()) { + logger.debug("Found init method on class [" + targetClass.getName() + "]: " + element); + } + this.initMethods.add(element); + } + + this.destroyMethods = new LinkedHashSet(); + for (LifecycleElement element : destroyMethods) { + if (logger.isDebugEnabled()) { + logger.debug("Found destroy method on class [" + targetClass.getName() + "]: " + element); + } + this.destroyMethods.add(element); } } - public Collection getInitMethods() { - return this.initMethods; + public void checkConfigMembers(RootBeanDefinition beanDefinition) { + for (Iterator it = this.initMethods.iterator(); it.hasNext();) { + String methodIdentifier = it.next().getIdentifier(); + if (!beanDefinition.isExternallyManagedInitMethod(methodIdentifier)) { + beanDefinition.registerExternallyManagedInitMethod(methodIdentifier); + } + else { + it.remove(); + } + } + for (Iterator it = this.destroyMethods.iterator(); it.hasNext();) { + String methodIdentifier = it.next().getIdentifier(); + if (!beanDefinition.isExternallyManagedDestroyMethod(methodIdentifier)) { + beanDefinition.registerExternallyManagedDestroyMethod(methodIdentifier); + } + else { + it.remove(); + } + } } public void invokeInitMethods(Object target, String beanName) throws Throwable { @@ -269,17 +295,6 @@ public class InitDestroyAnnotationBeanPostProcessor } } - public void addDestroyMethod(Method method) { - LifecycleElement element = new LifecycleElement(method); - if (!this.destroyMethods.contains(element)) { - this.destroyMethods.addLast(element); - } - } - - public Collection getDestroyMethods() { - return this.destroyMethods; - } - public void invokeDestroyMethods(Object target, String beanName) throws Throwable { if (!this.destroyMethods.isEmpty()) { boolean debug = logger.isDebugEnabled(); diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java index fa0da8b6dcc..31c88151339 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java @@ -162,8 +162,8 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { public void destroy() { if (this.beanPostProcessors != null && !this.beanPostProcessors.isEmpty()) { - for (int i = this.beanPostProcessors.size() - 1; i >= 0; i--) { - this.beanPostProcessors.get(i).postProcessBeforeDestruction(this.bean, this.beanName); + for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) { + processor.postProcessBeforeDestruction(this.bean, this.beanName); } }