Skip to content

Commit 379d81d

Browse files
committed
Consistent thread-safe handling of manualSingletonNames Set
Closes gh-22896
1 parent 4b31feb commit 379d81d

File tree

1 file changed

+37
-28
lines changed

1 file changed

+37
-28
lines changed

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

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
import java.util.Optional;
4141
import java.util.Set;
4242
import java.util.concurrent.ConcurrentHashMap;
43+
import java.util.function.Consumer;
44+
import java.util.function.Predicate;
4345
import java.util.stream.Stream;
4446
import javax.inject.Provider;
4547

@@ -921,18 +923,14 @@ else if (!beanDefinition.equals(existingDefinition)) {
921923
updatedDefinitions.addAll(this.beanDefinitionNames);
922924
updatedDefinitions.add(beanName);
923925
this.beanDefinitionNames = updatedDefinitions;
924-
if (this.manualSingletonNames.contains(beanName)) {
925-
Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
926-
updatedSingletons.remove(beanName);
927-
this.manualSingletonNames = updatedSingletons;
928-
}
926+
removeManualSingletonName(beanName);
929927
}
930928
}
931929
else {
932930
// Still in startup registration phase
933931
this.beanDefinitionMap.put(beanName, beanDefinition);
934932
this.beanDefinitionNames.add(beanName);
935-
this.manualSingletonNames.remove(beanName);
933+
removeManualSingletonName(beanName);
936934
}
937935
this.frozenBeanDefinitionNames = null;
938936
}
@@ -1020,40 +1018,51 @@ protected boolean allowAliasOverriding() {
10201018
@Override
10211019
public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
10221020
super.registerSingleton(beanName, singletonObject);
1021+
updateManualSingletonNames(set -> set.add(beanName), set -> !this.beanDefinitionMap.containsKey(beanName));
1022+
clearByTypeCache();
1023+
}
1024+
1025+
@Override
1026+
public void destroySingletons() {
1027+
super.destroySingletons();
1028+
updateManualSingletonNames(Set::clear, set -> !set.isEmpty());
1029+
clearByTypeCache();
1030+
}
1031+
1032+
@Override
1033+
public void destroySingleton(String beanName) {
1034+
super.destroySingleton(beanName);
1035+
removeManualSingletonName(beanName);
1036+
clearByTypeCache();
1037+
}
1038+
1039+
private void removeManualSingletonName(String beanName) {
1040+
updateManualSingletonNames(set -> set.remove(beanName), set -> set.contains(beanName));
1041+
}
10231042

1043+
/**
1044+
* Update the factory's internal set of manual singleton names.
1045+
* @param action the modification action
1046+
* @param condition a precondition for the modification action
1047+
* (if this condition does not apply, the action can be skipped)
1048+
*/
1049+
private void updateManualSingletonNames(Consumer<Set<String>> action, Predicate<Set<String>> condition) {
10241050
if (hasBeanCreationStarted()) {
10251051
// Cannot modify startup-time collection elements anymore (for stable iteration)
10261052
synchronized (this.beanDefinitionMap) {
1027-
if (!this.beanDefinitionMap.containsKey(beanName)) {
1028-
Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames.size() + 1);
1029-
updatedSingletons.addAll(this.manualSingletonNames);
1030-
updatedSingletons.add(beanName);
1053+
if (condition.test(this.manualSingletonNames)) {
1054+
Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
1055+
action.accept(updatedSingletons);
10311056
this.manualSingletonNames = updatedSingletons;
10321057
}
10331058
}
10341059
}
10351060
else {
10361061
// Still in startup registration phase
1037-
if (!this.beanDefinitionMap.containsKey(beanName)) {
1038-
this.manualSingletonNames.add(beanName);
1062+
if (condition.test(this.manualSingletonNames)) {
1063+
action.accept(this.manualSingletonNames);
10391064
}
10401065
}
1041-
1042-
clearByTypeCache();
1043-
}
1044-
1045-
@Override
1046-
public void destroySingleton(String beanName) {
1047-
super.destroySingleton(beanName);
1048-
this.manualSingletonNames.remove(beanName);
1049-
clearByTypeCache();
1050-
}
1051-
1052-
@Override
1053-
public void destroySingletons() {
1054-
super.destroySingletons();
1055-
this.manualSingletonNames.clear();
1056-
clearByTypeCache();
10571066
}
10581067

10591068
/**

0 commit comments

Comments
 (0)