Consistent thread-safe handling of manualSingletonNames Set

Closes gh-22896
This commit is contained in:
Juergen Hoeller 2019-05-07 00:47:59 +02:00
parent 4b31feb243
commit 379d81da74
1 changed files with 42 additions and 33 deletions

View File

@ -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<String> 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<String> 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<Set<String>> action, Predicate<Set<String>> condition) {
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
if (condition.test(this.manualSingletonNames)) {
Set<String> 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.
*/