Do not cache PropertyDescriptors for autowireBean calls anymore, avoiding ClassLoader leaks

Issue: SPR-8956
This commit is contained in:
Juergen Hoeller
2012-11-08 23:11:15 +01:00
parent 9e22ac496d
commit e1d11ec99d
2 changed files with 45 additions and 23 deletions

View File

@@ -285,6 +285,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
// Use prototype bean definition, to avoid registering bean as dependent bean. // Use prototype bean definition, to avoid registering bean as dependent bean.
RootBeanDefinition bd = new RootBeanDefinition(beanClass); RootBeanDefinition bd = new RootBeanDefinition(beanClass);
bd.setScope(SCOPE_PROTOTYPE); bd.setScope(SCOPE_PROTOTYPE);
bd.allowCaching = false;
return (T) createBean(beanClass.getName(), bd, null); return (T) createBean(beanClass.getName(), bd, null);
} }
@@ -292,6 +293,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
// Use non-singleton bean definition, to avoid registering bean as dependent bean. // Use non-singleton bean definition, to avoid registering bean as dependent bean.
RootBeanDefinition bd = new RootBeanDefinition(ClassUtils.getUserClass(existingBean)); RootBeanDefinition bd = new RootBeanDefinition(ClassUtils.getUserClass(existingBean));
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bd.allowCaching = false;
BeanWrapper bw = new BeanWrapperImpl(existingBean); BeanWrapper bw = new BeanWrapperImpl(existingBean);
initBeanWrapper(bw); initBeanWrapper(bw);
populateBean(bd.getBeanClass().getName(), bd, bw); populateBean(bd.getBeanClass().getName(), bd, bw);
@@ -310,6 +312,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
if (bd == null) { if (bd == null) {
bd = new RootBeanDefinition(mbd); bd = new RootBeanDefinition(mbd);
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE); bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bd.allowCaching = false;
} }
BeanWrapper bw = new BeanWrapperImpl(existingBean); BeanWrapper bw = new BeanWrapperImpl(existingBean);
initBeanWrapper(bw); initBeanWrapper(bw);
@@ -1053,7 +1056,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* @param mbd the bean definition for the bean * @param mbd the bean definition for the bean
* @param bw BeanWrapper with bean instance * @param bw BeanWrapper with bean instance
*/ */
protected void populateBean(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw) { protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
PropertyValues pvs = mbd.getPropertyValues(); PropertyValues pvs = mbd.getPropertyValues();
if (bw == null) { if (bw == null) {
@@ -1109,7 +1112,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE); boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
if (hasInstAwareBpps || needsDepCheck) { if (hasInstAwareBpps || needsDepCheck) {
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw); PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) { if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) { if (bp instanceof InstantiationAwareBeanPostProcessor) {
@@ -1237,32 +1240,49 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
/** /**
* Extract a filtered set of PropertyDescriptors from the given BeanWrapper, * Extract a filtered set of PropertyDescriptors from the given BeanWrapper,
* excluding ignored dependency types or properties defined on ignored * excluding ignored dependency types or properties defined on ignored dependency interfaces.
* dependency interfaces. * @param bw the BeanWrapper the bean was created with
* @param cache whether to cache filtered PropertyDescriptors for the given bean Class
* @return the filtered PropertyDescriptors
* @see #isExcludedFromDependencyCheck
* @see #filterPropertyDescriptorsForDependencyCheck(org.springframework.beans.BeanWrapper)
*/
protected PropertyDescriptor[] filterPropertyDescriptorsForDependencyCheck(BeanWrapper bw, boolean cache) {
PropertyDescriptor[] filtered = this.filteredPropertyDescriptorsCache.get(bw.getWrappedClass());
if (filtered == null) {
if (cache) {
synchronized (this.filteredPropertyDescriptorsCache) {
filtered = this.filteredPropertyDescriptorsCache.get(bw.getWrappedClass());
if (filtered == null) {
filtered = filterPropertyDescriptorsForDependencyCheck(bw);
this.filteredPropertyDescriptorsCache.put(bw.getWrappedClass(), filtered);
}
}
}
else {
filtered = filterPropertyDescriptorsForDependencyCheck(bw);
}
}
return filtered;
}
/**
* Extract a filtered set of PropertyDescriptors from the given BeanWrapper,
* excluding ignored dependency types or properties defined on ignored dependency interfaces.
* @param bw the BeanWrapper the bean was created with * @param bw the BeanWrapper the bean was created with
* @return the filtered PropertyDescriptors * @return the filtered PropertyDescriptors
* @see #isExcludedFromDependencyCheck * @see #isExcludedFromDependencyCheck
*/ */
protected PropertyDescriptor[] filterPropertyDescriptorsForDependencyCheck(BeanWrapper bw) { protected PropertyDescriptor[] filterPropertyDescriptorsForDependencyCheck(BeanWrapper bw) {
PropertyDescriptor[] filtered = this.filteredPropertyDescriptorsCache.get(bw.getWrappedClass()); List<PropertyDescriptor> pds =
if (filtered == null) { new LinkedList<PropertyDescriptor>(Arrays.asList(bw.getPropertyDescriptors()));
synchronized (this.filteredPropertyDescriptorsCache) { for (Iterator<PropertyDescriptor> it = pds.iterator(); it.hasNext();) {
filtered = this.filteredPropertyDescriptorsCache.get(bw.getWrappedClass()); PropertyDescriptor pd = it.next();
if (filtered == null) { if (isExcludedFromDependencyCheck(pd)) {
List<PropertyDescriptor> pds = it.remove();
new LinkedList<PropertyDescriptor>(Arrays.asList(bw.getPropertyDescriptors()));
for (Iterator<PropertyDescriptor> it = pds.iterator(); it.hasNext();) {
PropertyDescriptor pd = it.next();
if (isExcludedFromDependencyCheck(pd)) {
it.remove();
}
}
filtered = pds.toArray(new PropertyDescriptor[pds.size()]);
this.filteredPropertyDescriptorsCache.put(bw.getWrappedClass(), filtered);
}
} }
} }
return filtered; return pds.toArray(new PropertyDescriptor[pds.size()]);
} }
/** /**

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2010 the original author or authors. * Copyright 2002-2012 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -56,7 +56,9 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
private BeanDefinitionHolder decoratedDefinition; private BeanDefinitionHolder decoratedDefinition;
boolean isFactoryMethodUnique; boolean allowCaching = true;
boolean isFactoryMethodUnique = false;
/** Package-visible field for caching the resolved constructor or factory method */ /** Package-visible field for caching the resolved constructor or factory method */
Object resolvedConstructorOrFactoryMethod; Object resolvedConstructorOrFactoryMethod;