Skip to content

Commit e1d11ec

Browse files
committed
Do not cache PropertyDescriptors for autowireBean calls anymore, avoiding ClassLoader leaks
Issue: SPR-8956
1 parent 9e22ac4 commit e1d11ec

File tree

2 files changed

+41
-19
lines changed

2 files changed

+41
-19
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -285,13 +285,15 @@ public <T> T createBean(Class<T> beanClass) throws BeansException {
285285
// Use prototype bean definition, to avoid registering bean as dependent bean.
286286
RootBeanDefinition bd = new RootBeanDefinition(beanClass);
287287
bd.setScope(SCOPE_PROTOTYPE);
288+
bd.allowCaching = false;
288289
return (T) createBean(beanClass.getName(), bd, null);
289290
}
290291

291292
public void autowireBean(Object existingBean) {
292293
// Use non-singleton bean definition, to avoid registering bean as dependent bean.
293294
RootBeanDefinition bd = new RootBeanDefinition(ClassUtils.getUserClass(existingBean));
294295
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
296+
bd.allowCaching = false;
295297
BeanWrapper bw = new BeanWrapperImpl(existingBean);
296298
initBeanWrapper(bw);
297299
populateBean(bd.getBeanClass().getName(), bd, bw);
@@ -310,6 +312,7 @@ public Object configureBean(Object existingBean, String beanName) throws BeansEx
310312
if (bd == null) {
311313
bd = new RootBeanDefinition(mbd);
312314
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
315+
bd.allowCaching = false;
313316
}
314317
BeanWrapper bw = new BeanWrapperImpl(existingBean);
315318
initBeanWrapper(bw);
@@ -1053,7 +1056,7 @@ protected BeanWrapper autowireConstructor(
10531056
* @param mbd the bean definition for the bean
10541057
* @param bw BeanWrapper with bean instance
10551058
*/
1056-
protected void populateBean(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw) {
1059+
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
10571060
PropertyValues pvs = mbd.getPropertyValues();
10581061

10591062
if (bw == null) {
@@ -1109,7 +1112,7 @@ protected void populateBean(String beanName, AbstractBeanDefinition mbd, BeanWra
11091112
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
11101113

11111114
if (hasInstAwareBpps || needsDepCheck) {
1112-
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw);
1115+
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
11131116
if (hasInstAwareBpps) {
11141117
for (BeanPostProcessor bp : getBeanPostProcessors()) {
11151118
if (bp instanceof InstantiationAwareBeanPostProcessor) {
@@ -1237,34 +1240,51 @@ protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, Be
12371240

12381241
/**
12391242
* Extract a filtered set of PropertyDescriptors from the given BeanWrapper,
1240-
* excluding ignored dependency types or properties defined on ignored
1241-
* dependency interfaces.
1243+
* excluding ignored dependency types or properties defined on ignored dependency interfaces.
12421244
* @param bw the BeanWrapper the bean was created with
1245+
* @param cache whether to cache filtered PropertyDescriptors for the given bean Class
12431246
* @return the filtered PropertyDescriptors
12441247
* @see #isExcludedFromDependencyCheck
1248+
* @see #filterPropertyDescriptorsForDependencyCheck(org.springframework.beans.BeanWrapper)
12451249
*/
1246-
protected PropertyDescriptor[] filterPropertyDescriptorsForDependencyCheck(BeanWrapper bw) {
1250+
protected PropertyDescriptor[] filterPropertyDescriptorsForDependencyCheck(BeanWrapper bw, boolean cache) {
12471251
PropertyDescriptor[] filtered = this.filteredPropertyDescriptorsCache.get(bw.getWrappedClass());
12481252
if (filtered == null) {
1249-
synchronized (this.filteredPropertyDescriptorsCache) {
1250-
filtered = this.filteredPropertyDescriptorsCache.get(bw.getWrappedClass());
1251-
if (filtered == null) {
1252-
List<PropertyDescriptor> pds =
1253-
new LinkedList<PropertyDescriptor>(Arrays.asList(bw.getPropertyDescriptors()));
1254-
for (Iterator<PropertyDescriptor> it = pds.iterator(); it.hasNext();) {
1255-
PropertyDescriptor pd = it.next();
1256-
if (isExcludedFromDependencyCheck(pd)) {
1257-
it.remove();
1258-
}
1253+
if (cache) {
1254+
synchronized (this.filteredPropertyDescriptorsCache) {
1255+
filtered = this.filteredPropertyDescriptorsCache.get(bw.getWrappedClass());
1256+
if (filtered == null) {
1257+
filtered = filterPropertyDescriptorsForDependencyCheck(bw);
1258+
this.filteredPropertyDescriptorsCache.put(bw.getWrappedClass(), filtered);
12591259
}
1260-
filtered = pds.toArray(new PropertyDescriptor[pds.size()]);
1261-
this.filteredPropertyDescriptorsCache.put(bw.getWrappedClass(), filtered);
12621260
}
12631261
}
1262+
else {
1263+
filtered = filterPropertyDescriptorsForDependencyCheck(bw);
1264+
}
12641265
}
12651266
return filtered;
12661267
}
12671268

1269+
/**
1270+
* Extract a filtered set of PropertyDescriptors from the given BeanWrapper,
1271+
* excluding ignored dependency types or properties defined on ignored dependency interfaces.
1272+
* @param bw the BeanWrapper the bean was created with
1273+
* @return the filtered PropertyDescriptors
1274+
* @see #isExcludedFromDependencyCheck
1275+
*/
1276+
protected PropertyDescriptor[] filterPropertyDescriptorsForDependencyCheck(BeanWrapper bw) {
1277+
List<PropertyDescriptor> pds =
1278+
new LinkedList<PropertyDescriptor>(Arrays.asList(bw.getPropertyDescriptors()));
1279+
for (Iterator<PropertyDescriptor> it = pds.iterator(); it.hasNext();) {
1280+
PropertyDescriptor pd = it.next();
1281+
if (isExcludedFromDependencyCheck(pd)) {
1282+
it.remove();
1283+
}
1284+
}
1285+
return pds.toArray(new PropertyDescriptor[pds.size()]);
1286+
}
1287+
12681288
/**
12691289
* Determine whether the given bean property is excluded from dependency checks.
12701290
* <p>This implementation excludes properties defined by CGLIB and

spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2010 the original author or authors.
2+
* Copyright 2002-2012 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -56,7 +56,9 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
5656

5757
private BeanDefinitionHolder decoratedDefinition;
5858

59-
boolean isFactoryMethodUnique;
59+
boolean allowCaching = true;
60+
61+
boolean isFactoryMethodUnique = false;
6062

6163
/** Package-visible field for caching the resolved constructor or factory method */
6264
Object resolvedConstructorOrFactoryMethod;

0 commit comments

Comments
 (0)