Skip to content

Commit c248f94

Browse files
committed
Cache bean type next to primary bean names (on singleton creation)
This avoids singleton access for type checks in hasPrimaryConflict. Closes gh-35330
1 parent 19d5ec6 commit c248f94

File tree

1 file changed

+21
-7
lines changed

1 file changed

+21
-7
lines changed

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

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
import org.springframework.beans.factory.BeanFactoryUtils;
5959
import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
6060
import org.springframework.beans.factory.CannotLoadBeanClassException;
61+
import org.springframework.beans.factory.FactoryBean;
6162
import org.springframework.beans.factory.InjectionPoint;
6263
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
6364
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
@@ -196,8 +197,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
196197
/** Map from bean name to merged BeanDefinitionHolder. */
197198
private final Map<String, BeanDefinitionHolder> mergedBeanDefinitionHolders = new ConcurrentHashMap<>(256);
198199

199-
/** Set of bean definition names with a primary marker. */
200-
private final Set<String> primaryBeanNames = ConcurrentHashMap.newKeySet(16);
200+
/** Map of bean definition names with a primary marker plus corresponding type. */
201+
private final Map<String, Class<?>> primaryBeanNamesWithType = new ConcurrentHashMap<>(16);
201202

202203
/** Map of singleton and non-singleton bean names, keyed by dependency type. */
203204
private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);
@@ -1037,7 +1038,7 @@ protected Object obtainInstanceFromSupplier(Supplier<?> supplier, String beanNam
10371038
protected void cacheMergedBeanDefinition(RootBeanDefinition mbd, String beanName) {
10381039
super.cacheMergedBeanDefinition(mbd, beanName);
10391040
if (mbd.isPrimary()) {
1040-
this.primaryBeanNames.add(beanName);
1041+
this.primaryBeanNamesWithType.put(beanName, Void.class);
10411042
}
10421043
}
10431044

@@ -1313,7 +1314,7 @@ else if (isConfigurationFrozen()) {
13131314

13141315
// Cache a primary marker for the given bean.
13151316
if (beanDefinition.isPrimary()) {
1316-
this.primaryBeanNames.add(beanName);
1317+
this.primaryBeanNamesWithType.put(beanName, Void.class);
13171318
}
13181319
}
13191320

@@ -1405,7 +1406,7 @@ protected void resetBeanDefinition(String beanName) {
14051406
destroySingleton(beanName);
14061407

14071408
// Remove a cached primary marker for the given bean.
1408-
this.primaryBeanNames.remove(beanName);
1409+
this.primaryBeanNamesWithType.remove(beanName);
14091410

14101411
// Notify all post-processors that the specified bean definition has been reset.
14111412
for (MergedBeanDefinitionPostProcessor processor : getBeanPostProcessorCache().mergedDefinition) {
@@ -1458,9 +1459,18 @@ protected void checkForAliasCircle(String name, String alias) {
14581459
@Override
14591460
protected void addSingleton(String beanName, Object singletonObject) {
14601461
super.addSingleton(beanName, singletonObject);
1462+
14611463
Predicate<Class<?>> filter = (beanType -> beanType != Object.class && beanType.isInstance(singletonObject));
14621464
this.allBeanNamesByType.keySet().removeIf(filter);
14631465
this.singletonBeanNamesByType.keySet().removeIf(filter);
1466+
1467+
if (this.primaryBeanNamesWithType.containsKey(beanName) && singletonObject.getClass() != NullBean.class) {
1468+
Class<?> beanType = (singletonObject instanceof FactoryBean<?> fb ?
1469+
getTypeForFactoryBean(fb) : singletonObject.getClass());
1470+
if (beanType != null) {
1471+
this.primaryBeanNamesWithType.put(beanName, beanType);
1472+
}
1473+
}
14641474
}
14651475

14661476
@Override
@@ -2268,8 +2278,12 @@ private boolean isSelfReference(@Nullable String beanName, @Nullable String cand
22682278
* not matching the given bean name.
22692279
*/
22702280
private boolean hasPrimaryConflict(String beanName, Class<?> dependencyType) {
2271-
for (String candidate : this.primaryBeanNames) {
2272-
if (isTypeMatch(candidate, dependencyType) && !candidate.equals(beanName)) {
2281+
for (Map.Entry<String, Class<?>> candidate : this.primaryBeanNamesWithType.entrySet()) {
2282+
String candidateName = candidate.getKey();
2283+
Class<?> candidateType = candidate.getValue();
2284+
if (!candidateName.equals(beanName) && (candidateType != Void.class ?
2285+
dependencyType.isAssignableFrom(candidateType) : // cached singleton class for primary bean
2286+
isTypeMatch(candidateName, dependencyType))) { // not instantiated yet or not a singleton
22732287
return true;
22742288
}
22752289
}

0 commit comments

Comments
 (0)