From 379d81da74f0a304361aee0b9f58c80a1995b929 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 7 May 2019 00:47:59 +0200 Subject: [PATCH] Consistent thread-safe handling of manualSingletonNames Set Closes gh-22896 --- .../support/DefaultListableBeanFactory.java | 75 +++++++++++-------- 1 file changed, 42 insertions(+), 33 deletions(-) diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java index f2bcbe94e3..3ce1e4c4d3 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java @@ -40,6 +40,8 @@ import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Consumer; +import java.util.function.Predicate; import java.util.stream.Stream; import javax.inject.Provider; @@ -921,18 +923,14 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; - if (this.manualSingletonNames.contains(beanName)) { - Set updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames); - updatedSingletons.remove(beanName); - this.manualSingletonNames = updatedSingletons; - } + removeManualSingletonName(beanName); } } else { // Still in startup registration phase this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); - this.manualSingletonNames.remove(beanName); + removeManualSingletonName(beanName); } this.frozenBeanDefinitionNames = null; } @@ -1020,42 +1018,53 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto @Override public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException { super.registerSingleton(beanName, singletonObject); - - if (hasBeanCreationStarted()) { - // Cannot modify startup-time collection elements anymore (for stable iteration) - synchronized (this.beanDefinitionMap) { - if (!this.beanDefinitionMap.containsKey(beanName)) { - Set updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames.size() + 1); - updatedSingletons.addAll(this.manualSingletonNames); - updatedSingletons.add(beanName); - this.manualSingletonNames = updatedSingletons; - } - } - } - else { - // Still in startup registration phase - if (!this.beanDefinitionMap.containsKey(beanName)) { - this.manualSingletonNames.add(beanName); - } - } - - clearByTypeCache(); - } - - @Override - public void destroySingleton(String beanName) { - super.destroySingleton(beanName); - this.manualSingletonNames.remove(beanName); + updateManualSingletonNames(set -> set.add(beanName), set -> !this.beanDefinitionMap.containsKey(beanName)); clearByTypeCache(); } @Override public void destroySingletons() { super.destroySingletons(); - this.manualSingletonNames.clear(); + updateManualSingletonNames(Set::clear, set -> !set.isEmpty()); clearByTypeCache(); } + @Override + public void destroySingleton(String beanName) { + super.destroySingleton(beanName); + removeManualSingletonName(beanName); + clearByTypeCache(); + } + + private void removeManualSingletonName(String beanName) { + updateManualSingletonNames(set -> set.remove(beanName), set -> set.contains(beanName)); + } + + /** + * Update the factory's internal set of manual singleton names. + * @param action the modification action + * @param condition a precondition for the modification action + * (if this condition does not apply, the action can be skipped) + */ + private void updateManualSingletonNames(Consumer> action, Predicate> condition) { + if (hasBeanCreationStarted()) { + // Cannot modify startup-time collection elements anymore (for stable iteration) + synchronized (this.beanDefinitionMap) { + if (condition.test(this.manualSingletonNames)) { + Set updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames); + action.accept(updatedSingletons); + this.manualSingletonNames = updatedSingletons; + } + } + } + else { + // Still in startup registration phase + if (condition.test(this.manualSingletonNames)) { + action.accept(this.manualSingletonNames); + } + } + } + /** * Remove any assumptions about by-type mappings. */