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

This commit is contained in:
Juergen Hoeller 2009-11-19 23:49:10 +00:00
parent 4375b9c89a
commit 3b9605bc57
3 changed files with 114 additions and 95 deletions

View File

@ -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<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
Class<?> targetClass = clazz;
do {
LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<InjectionMetadata.InjectedElement>();
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<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
Class<?> targetClass = clazz;
do {
LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<InjectionMetadata.InjectedElement>();
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<? extends Annotation> type : this.autowiredAnnotationTypes) {
Annotation annotation = ao.getAnnotation(type);

View File

@ -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<LifecycleElement> it = metadata.getInitMethods().iterator(); it.hasNext();) {
String methodIdentifier = it.next().getIdentifier();
if (!beanDefinition.isExternallyManagedInitMethod(methodIdentifier)) {
beanDefinition.registerExternallyManagedInitMethod(methodIdentifier);
}
else {
it.remove();
}
}
for (Iterator<LifecycleElement> 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<LifecycleElement> initMethods = new LinkedList<LifecycleElement>();
LinkedList<LifecycleElement> destroyMethods = new LinkedList<LifecycleElement>();
Class<?> targetClass = clazz;
do {
LinkedList<LifecycleElement> currInitMethods = new LinkedList<LifecycleElement>();
LinkedList<LifecycleElement> currDestroyMethods = new LinkedList<LifecycleElement>();
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<LifecycleElement> initMethods = new LinkedList<LifecycleElement>();
private final Set<LifecycleElement> initMethods;
private final LinkedList<LifecycleElement> destroyMethods = new LinkedList<LifecycleElement>();
private final Set<LifecycleElement> 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<LifecycleElement> initMethods,
Collection<LifecycleElement> destroyMethods) {
this.initMethods = new LinkedHashSet<LifecycleElement>();
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<LifecycleElement>();
for (LifecycleElement element : destroyMethods) {
if (logger.isDebugEnabled()) {
logger.debug("Found destroy method on class [" + targetClass.getName() + "]: " + element);
}
this.destroyMethods.add(element);
}
}
public Collection<LifecycleElement> getInitMethods() {
return this.initMethods;
public void checkConfigMembers(RootBeanDefinition beanDefinition) {
for (Iterator<LifecycleElement> it = this.initMethods.iterator(); it.hasNext();) {
String methodIdentifier = it.next().getIdentifier();
if (!beanDefinition.isExternallyManagedInitMethod(methodIdentifier)) {
beanDefinition.registerExternallyManagedInitMethod(methodIdentifier);
}
else {
it.remove();
}
}
for (Iterator<LifecycleElement> 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<LifecycleElement> getDestroyMethods() {
return this.destroyMethods;
}
public void invokeDestroyMethods(Object target, String beanName) throws Throwable {
if (!this.destroyMethods.isEmpty()) {
boolean debug = logger.isDebugEnabled();

View File

@ -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);
}
}