1
1
/*
2
- * Copyright 2002-2023 the original author or authors.
2
+ * Copyright 2002-2024 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
29
29
import java .util .ArrayList ;
30
30
import java .util .Arrays ;
31
31
import java .util .Collection ;
32
+ import java .util .Collections ;
32
33
import java .util .Comparator ;
33
34
import java .util .IdentityHashMap ;
34
35
import java .util .Iterator ;
@@ -167,6 +168,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
167
168
/** Map from bean name to merged BeanDefinitionHolder. */
168
169
private final Map <String , BeanDefinitionHolder > mergedBeanDefinitionHolders = new ConcurrentHashMap <>(256 );
169
170
171
+ // Set of bean definition names with a primary marker. */
172
+ private final Set <String > primaryBeanNames = Collections .newSetFromMap (new ConcurrentHashMap <>(16 ));
173
+
170
174
/** Map of singleton and non-singleton bean names, keyed by dependency type. */
171
175
private final Map <Class <?>, String []> allBeanNamesByType = new ConcurrentHashMap <>(64 );
172
176
@@ -1084,6 +1088,11 @@ else if (!beanDefinition.equals(existingDefinition)) {
1084
1088
else if (isConfigurationFrozen ()) {
1085
1089
clearByTypeCache ();
1086
1090
}
1091
+
1092
+ // Cache a primary marker for the given bean.
1093
+ if (beanDefinition .isPrimary ()) {
1094
+ this .primaryBeanNames .add (beanName );
1095
+ }
1087
1096
}
1088
1097
1089
1098
@ Override
@@ -1135,6 +1144,9 @@ protected void resetBeanDefinition(String beanName) {
1135
1144
// (e.g. the default StaticMessageSource in a StaticApplicationContext).
1136
1145
destroySingleton (beanName );
1137
1146
1147
+ // Remove a cached primary marker for the given bean.
1148
+ this .primaryBeanNames .remove (beanName );
1149
+
1138
1150
// Notify all post-processors that the specified bean definition has been reset.
1139
1151
for (MergedBeanDefinitionPostProcessor processor : getBeanPostProcessorCache ().mergedDefinition ) {
1140
1152
processor .resetBeanDefinition (beanName );
@@ -1388,15 +1400,27 @@ public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable Str
1388
1400
}
1389
1401
}
1390
1402
1391
- // Step 3a: multiple beans as stream / array / standard collection / plain map
1403
+ // Step 3: shortcut for declared dependency name matching target bean name
1404
+ String dependencyName = descriptor .getDependencyName ();
1405
+ if (dependencyName != null && containsBean (dependencyName ) &&
1406
+ isTypeMatch (dependencyName , type ) && isAutowireCandidate (dependencyName , descriptor ) &&
1407
+ !hasPrimaryConflict (dependencyName , type ) && !isSelfReference (beanName , dependencyName )) {
1408
+ if (autowiredBeanNames != null ) {
1409
+ autowiredBeanNames .add (dependencyName );
1410
+ }
1411
+ Object dependencyBean = getBean (dependencyName );
1412
+ return resolveInstance (dependencyBean , descriptor , type , dependencyName );
1413
+ }
1414
+
1415
+ // Step 4a: multiple beans as stream / array / standard collection / plain map
1392
1416
Object multipleBeans = resolveMultipleBeans (descriptor , beanName , autowiredBeanNames , typeConverter );
1393
1417
if (multipleBeans != null ) {
1394
1418
return multipleBeans ;
1395
1419
}
1396
- // Step 3b : direct bean matches, possibly direct beans of type Collection / Map
1420
+ // Step 4b : direct bean matches, possibly direct beans of type Collection / Map
1397
1421
Map <String , Object > matchingBeans = findAutowireCandidates (beanName , type , descriptor );
1398
1422
if (matchingBeans .isEmpty ()) {
1399
- // Step 3c (fallback): custom Collection / Map declarations for collecting multiple beans
1423
+ // Step 4c (fallback): custom Collection / Map declarations for collecting multiple beans
1400
1424
multipleBeans = resolveMultipleBeansFallback (descriptor , beanName , autowiredBeanNames , typeConverter );
1401
1425
if (multipleBeans != null ) {
1402
1426
return multipleBeans ;
@@ -1411,7 +1435,7 @@ public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable Str
1411
1435
String autowiredBeanName ;
1412
1436
Object instanceCandidate ;
1413
1437
1414
- // Step 4 : determine single candidate
1438
+ // Step 5 : determine single candidate
1415
1439
if (matchingBeans .size () > 1 ) {
1416
1440
autowiredBeanName = determineAutowireCandidate (matchingBeans , descriptor );
1417
1441
if (autowiredBeanName == null ) {
@@ -1435,31 +1459,37 @@ public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable Str
1435
1459
instanceCandidate = entry .getValue ();
1436
1460
}
1437
1461
1438
- // Step 5 : validate single result
1462
+ // Step 6 : validate single result
1439
1463
if (autowiredBeanNames != null ) {
1440
1464
autowiredBeanNames .add (autowiredBeanName );
1441
1465
}
1442
1466
if (instanceCandidate instanceof Class ) {
1443
1467
instanceCandidate = descriptor .resolveCandidate (autowiredBeanName , type , this );
1444
1468
}
1445
- Object result = instanceCandidate ;
1446
- if (result instanceof NullBean ) {
1447
- if (isRequired (descriptor )) {
1448
- // Raise exception if null encountered for required injection point
1449
- raiseNoMatchingBeanFound (type , descriptor .getResolvableType (), descriptor );
1450
- }
1451
- result = null ;
1452
- }
1453
- if (!ClassUtils .isAssignableValue (type , result )) {
1454
- throw new BeanNotOfRequiredTypeException (autowiredBeanName , type , instanceCandidate .getClass ());
1455
- }
1456
- return result ;
1469
+ return resolveInstance (instanceCandidate , descriptor , type , autowiredBeanName );
1457
1470
}
1458
1471
finally {
1459
1472
ConstructorResolver .setCurrentInjectionPoint (previousInjectionPoint );
1460
1473
}
1461
1474
}
1462
1475
1476
+ @ Nullable
1477
+ private Object resolveInstance (Object candidate , DependencyDescriptor descriptor , Class <?> type , String name ) {
1478
+ Object result = candidate ;
1479
+ if (result instanceof NullBean ) {
1480
+ // Raise exception if null encountered for required injection point
1481
+ if (isRequired (descriptor )) {
1482
+ raiseNoMatchingBeanFound (type , descriptor .getResolvableType (), descriptor );
1483
+ }
1484
+ result = null ;
1485
+ }
1486
+ if (!ClassUtils .isAssignableValue (type , result )) {
1487
+ throw new BeanNotOfRequiredTypeException (name , type , candidate .getClass ());
1488
+ }
1489
+ return result ;
1490
+
1491
+ }
1492
+
1463
1493
@ Nullable
1464
1494
private Object resolveMultipleBeans (DependencyDescriptor descriptor , @ Nullable String beanName ,
1465
1495
@ Nullable Set <String > autowiredBeanNames , @ Nullable TypeConverter typeConverter ) {
@@ -1712,20 +1742,27 @@ else if (containsSingleton(candidateName) || (descriptor instanceof StreamDepend
1712
1742
@ Nullable
1713
1743
protected String determineAutowireCandidate (Map <String , Object > candidates , DependencyDescriptor descriptor ) {
1714
1744
Class <?> requiredType = descriptor .getDependencyType ();
1745
+ // Step 1: check primary candidate
1715
1746
String primaryCandidate = determinePrimaryCandidate (candidates , requiredType );
1716
1747
if (primaryCandidate != null ) {
1717
1748
return primaryCandidate ;
1718
1749
}
1750
+ // Step 2: check bean name match
1751
+ for (String candidateName : candidates .keySet ()) {
1752
+ if (matchesBeanName (candidateName , descriptor .getDependencyName ())) {
1753
+ return candidateName ;
1754
+ }
1755
+ }
1756
+ // Step 3: check highest priority candidate
1719
1757
String priorityCandidate = determineHighestPriorityCandidate (candidates , requiredType );
1720
1758
if (priorityCandidate != null ) {
1721
1759
return priorityCandidate ;
1722
1760
}
1723
- // Fallback : pick directly registered dependency or qualified bean name match
1761
+ // Step 4 : pick directly registered dependency
1724
1762
for (Map .Entry <String , Object > entry : candidates .entrySet ()) {
1725
1763
String candidateName = entry .getKey ();
1726
1764
Object beanInstance = entry .getValue ();
1727
- if ((beanInstance != null && this .resolvableDependencies .containsValue (beanInstance )) ||
1728
- matchesBeanName (candidateName , descriptor .getDependencyName ())) {
1765
+ if (beanInstance != null && this .resolvableDependencies .containsValue (beanInstance )) {
1729
1766
return candidateName ;
1730
1767
}
1731
1768
}
@@ -1866,6 +1903,21 @@ private boolean isSelfReference(@Nullable String beanName, @Nullable String cand
1866
1903
beanName .equals (getMergedLocalBeanDefinition (candidateName ).getFactoryBeanName ()))));
1867
1904
}
1868
1905
1906
+ /**
1907
+ * Determine whether there is a primary bean registered for the given dependency type,
1908
+ * not matching the given bean name.
1909
+ */
1910
+ @ Nullable
1911
+ private boolean hasPrimaryConflict (String beanName , Class <?> dependencyType ) {
1912
+ for (String candidate : this .primaryBeanNames ) {
1913
+ if (isTypeMatch (candidate , dependencyType ) && !candidate .equals (beanName )) {
1914
+ return true ;
1915
+ }
1916
+ }
1917
+ return (getParentBeanFactory () instanceof DefaultListableBeanFactory parent &&
1918
+ parent .hasPrimaryConflict (beanName , dependencyType ));
1919
+ }
1920
+
1869
1921
/**
1870
1922
* Raise a NoSuchBeanDefinitionException or BeanNotOfRequiredTypeException
1871
1923
* for an unresolvable dependency.
0 commit comments