Skip to content

Commit 1756f83

Browse files
committed
Defensively expect concurrent registration of BeanPostProcessors
Declaring beanPostProcessors (and also embeddedValueResolvers) as CopyOnWriteArrayList prevents ConcurrentModificationExceptions in case of concurrent registration/access attempts. Issue: SPR-17286
1 parent d94e922 commit 1756f83

File tree

1 file changed

+9
-10
lines changed

1 file changed

+9
-10
lines changed

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

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@
2929
import java.util.HashSet;
3030
import java.util.LinkedHashMap;
3131
import java.util.LinkedHashSet;
32-
import java.util.LinkedList;
3332
import java.util.List;
3433
import java.util.Map;
3534
import java.util.Set;
3635
import java.util.concurrent.ConcurrentHashMap;
36+
import java.util.concurrent.CopyOnWriteArrayList;
3737

3838
import org.springframework.beans.BeanUtils;
3939
import org.springframework.beans.BeanWrapper;
@@ -145,16 +145,16 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
145145
private TypeConverter typeConverter;
146146

147147
/** String resolvers to apply e.g. to annotation attribute values. */
148-
private final List<StringValueResolver> embeddedValueResolvers = new LinkedList<>();
148+
private final List<StringValueResolver> embeddedValueResolvers = new CopyOnWriteArrayList<>();
149149

150150
/** BeanPostProcessors to apply in createBean. */
151-
private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();
151+
private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();
152152

153153
/** Indicates whether any InstantiationAwareBeanPostProcessors have been registered. */
154-
private boolean hasInstantiationAwareBeanPostProcessors;
154+
private volatile boolean hasInstantiationAwareBeanPostProcessors;
155155

156156
/** Indicates whether any DestructionAwareBeanPostProcessors have been registered. */
157-
private boolean hasDestructionAwareBeanPostProcessors;
157+
private volatile boolean hasDestructionAwareBeanPostProcessors;
158158

159159
/** Map from scope identifier String to corresponding Scope. */
160160
private final Map<String, Scope> scopes = new LinkedHashMap<>(8);
@@ -850,14 +850,17 @@ public String resolveEmbeddedValue(@Nullable String value) {
850850
@Override
851851
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
852852
Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
853+
// Remove from old position, if any
853854
this.beanPostProcessors.remove(beanPostProcessor);
854-
this.beanPostProcessors.add(beanPostProcessor);
855+
// Track whether it is instantiation/destruction aware
855856
if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
856857
this.hasInstantiationAwareBeanPostProcessors = true;
857858
}
858859
if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
859860
this.hasDestructionAwareBeanPostProcessors = true;
860861
}
862+
// Add to end of list
863+
this.beanPostProcessors.add(beanPostProcessor);
861864
}
862865

863866
@Override
@@ -988,7 +991,6 @@ public void copyConfigurationFrom(ConfigurableBeanFactory otherFactory) {
988991
@Override
989992
public BeanDefinition getMergedBeanDefinition(String name) throws BeansException {
990993
String beanName = transformedBeanName(name);
991-
992994
// Efficiently check whether bean definition exists in this factory.
993995
if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
994996
return ((ConfigurableBeanFactory) getParentBeanFactory()).getMergedBeanDefinition(beanName);
@@ -1000,18 +1002,15 @@ public BeanDefinition getMergedBeanDefinition(String name) throws BeansException
10001002
@Override
10011003
public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException {
10021004
String beanName = transformedBeanName(name);
1003-
10041005
Object beanInstance = getSingleton(beanName, false);
10051006
if (beanInstance != null) {
10061007
return (beanInstance instanceof FactoryBean);
10071008
}
1008-
10091009
// No singleton instance found -> check bean definition.
10101010
if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
10111011
// No bean definition found in this factory -> delegate to parent.
10121012
return ((ConfigurableBeanFactory) getParentBeanFactory()).isFactoryBean(name);
10131013
}
1014-
10151014
return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName));
10161015
}
10171016

0 commit comments

Comments
 (0)