@@ -976,38 +976,47 @@ public <T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType) throws Bea
976
976
return null ;
977
977
}
978
978
979
+ @ SuppressWarnings ("unchecked" )
979
980
private <T > NamedBeanHolder <T > resolveNamedBean (Class <T > requiredType , Object ... args ) throws BeansException {
980
981
Assert .notNull (requiredType , "Required type must not be null" );
981
- String [] beanNames = getBeanNamesForType (requiredType );
982
+ String [] candidateNames = getBeanNamesForType (requiredType );
982
983
983
- if (beanNames .length > 1 ) {
984
+ if (candidateNames .length > 1 ) {
984
985
ArrayList <String > autowireCandidates = new ArrayList <>();
985
- for (String beanName : beanNames ) {
986
+ for (String beanName : candidateNames ) {
986
987
if (!containsBeanDefinition (beanName ) || getBeanDefinition (beanName ).isAutowireCandidate ()) {
987
988
autowireCandidates .add (beanName );
988
989
}
989
990
}
990
991
if (!autowireCandidates .isEmpty ()) {
991
- beanNames = autowireCandidates .toArray (new String [autowireCandidates .size ()]);
992
+ candidateNames = autowireCandidates .toArray (new String [autowireCandidates .size ()]);
992
993
}
993
994
}
994
995
995
- if (beanNames .length == 1 ) {
996
- String beanName = beanNames [0 ];
996
+ if (candidateNames .length == 1 ) {
997
+ String beanName = candidateNames [0 ];
997
998
return new NamedBeanHolder <>(beanName , getBean (beanName , requiredType , args ));
998
999
}
999
- else if (beanNames .length > 1 ) {
1000
- Map <String , Object > candidates = new LinkedHashMap <>();
1001
- for (String beanName : beanNames ) {
1002
- candidates .put (beanName , getBean (beanName , requiredType , args ));
1000
+ else if (candidateNames .length > 1 ) {
1001
+ Map <String , Object > candidates = new LinkedHashMap <>(candidateNames .length );
1002
+ for (String candidateName : candidateNames ) {
1003
+ if (containsSingleton (candidateName )) {
1004
+ candidates .put (candidateName , getBean (candidateName , requiredType , args ));
1005
+ }
1006
+ else {
1007
+ candidates .put (candidateName , getType (candidateName ));
1008
+ }
1003
1009
}
1004
- String primaryCandidate = determinePrimaryCandidate (candidates , requiredType );
1005
- if (primaryCandidate ! = null ) {
1006
- return new NamedBeanHolder <>( primaryCandidate , getBean ( primaryCandidate , requiredType , args ) );
1010
+ String candidateName = determinePrimaryCandidate (candidates , requiredType );
1011
+ if (candidateName = = null ) {
1012
+ candidateName = determineHighestPriorityCandidate ( candidates , requiredType );
1007
1013
}
1008
- String priorityCandidate = determineHighestPriorityCandidate (candidates , requiredType );
1009
- if (priorityCandidate != null ) {
1010
- return new NamedBeanHolder <>(priorityCandidate , getBean (priorityCandidate , requiredType , args ));
1014
+ if (candidateName != null ) {
1015
+ Object beanInstance = candidates .get (candidateName );
1016
+ if (beanInstance instanceof Class ) {
1017
+ beanInstance = getBean (candidateName , requiredType , args );
1018
+ }
1019
+ return new NamedBeanHolder <>(candidateName , (T ) beanInstance );
1011
1020
}
1012
1021
throw new NoUniqueBeanDefinitionException (requiredType , candidates .keySet ());
1013
1022
}
@@ -1076,9 +1085,13 @@ public Object doResolveDependency(DependencyDescriptor descriptor, String beanNa
1076
1085
}
1077
1086
return null ;
1078
1087
}
1088
+
1089
+ String autowiredBeanName ;
1090
+ Object instanceCandidate ;
1091
+
1079
1092
if (matchingBeans .size () > 1 ) {
1080
- String primaryBeanName = determineAutowireCandidate (matchingBeans , descriptor );
1081
- if (primaryBeanName == null ) {
1093
+ autowiredBeanName = determineAutowireCandidate (matchingBeans , descriptor );
1094
+ if (autowiredBeanName == null ) {
1082
1095
if (descriptor .isRequired () || !indicatesMultipleBeans (type )) {
1083
1096
return descriptor .resolveNotUnique (type , matchingBeans );
1084
1097
}
@@ -1089,17 +1102,20 @@ public Object doResolveDependency(DependencyDescriptor descriptor, String beanNa
1089
1102
return null ;
1090
1103
}
1091
1104
}
1092
- if (autowiredBeanNames != null ) {
1093
- autowiredBeanNames .add (primaryBeanName );
1094
- }
1095
- return matchingBeans .get (primaryBeanName );
1105
+ instanceCandidate = matchingBeans .get (autowiredBeanName );
1096
1106
}
1097
- // We have exactly one match.
1098
- Map .Entry <String , Object > entry = matchingBeans .entrySet ().iterator ().next ();
1107
+ else {
1108
+ // We have exactly one match.
1109
+ Map .Entry <String , Object > entry = matchingBeans .entrySet ().iterator ().next ();
1110
+ autowiredBeanName = entry .getKey ();
1111
+ instanceCandidate = entry .getValue ();
1112
+ }
1113
+
1099
1114
if (autowiredBeanNames != null ) {
1100
- autowiredBeanNames .add (entry . getKey () );
1115
+ autowiredBeanNames .add (autowiredBeanName );
1101
1116
}
1102
- return entry .getValue ();
1117
+ return (instanceCandidate instanceof Class ?
1118
+ descriptor .resolveCandidate (autowiredBeanName , type , this ) : instanceCandidate );
1103
1119
}
1104
1120
finally {
1105
1121
ConstructorResolver .setCurrentInjectionPoint (previousInjectionPoint );
@@ -1112,9 +1128,8 @@ private Object resolveMultipleBeans(DependencyDescriptor descriptor, String bean
1112
1128
Class <?> type = descriptor .getDependencyType ();
1113
1129
if (type .isArray ()) {
1114
1130
Class <?> componentType = type .getComponentType ();
1115
- DependencyDescriptor targetDesc = new DependencyDescriptor (descriptor );
1116
- targetDesc .increaseNestingLevel ();
1117
- Map <String , Object > matchingBeans = findAutowireCandidates (beanName , componentType , targetDesc );
1131
+ Map <String , Object > matchingBeans = findAutowireCandidates (beanName , componentType ,
1132
+ new MultiElementDependencyDescriptor (descriptor ));
1118
1133
if (matchingBeans .isEmpty ()) {
1119
1134
return null ;
1120
1135
}
@@ -1133,9 +1148,8 @@ else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
1133
1148
if (elementType == null ) {
1134
1149
return null ;
1135
1150
}
1136
- DependencyDescriptor targetDesc = new DependencyDescriptor (descriptor );
1137
- targetDesc .increaseNestingLevel ();
1138
- Map <String , Object > matchingBeans = findAutowireCandidates (beanName , elementType , targetDesc );
1151
+ Map <String , Object > matchingBeans = findAutowireCandidates (beanName , elementType ,
1152
+ new MultiElementDependencyDescriptor (descriptor ));
1139
1153
if (matchingBeans .isEmpty ()) {
1140
1154
return null ;
1141
1155
}
@@ -1158,9 +1172,8 @@ else if (Map.class.isAssignableFrom(type) && type.isInterface()) {
1158
1172
if (valueType == null ) {
1159
1173
return null ;
1160
1174
}
1161
- DependencyDescriptor targetDesc = new DependencyDescriptor (descriptor );
1162
- targetDesc .increaseNestingLevel ();
1163
- Map <String , Object > matchingBeans = findAutowireCandidates (beanName , valueType , targetDesc );
1175
+ Map <String , Object > matchingBeans = findAutowireCandidates (beanName , valueType ,
1176
+ new MultiElementDependencyDescriptor (descriptor ));
1164
1177
if (matchingBeans .isEmpty ()) {
1165
1178
return null ;
1166
1179
}
@@ -1229,79 +1242,94 @@ protected Map<String, Object> findAutowireCandidates(
1229
1242
}
1230
1243
for (String candidateName : candidateNames ) {
1231
1244
if (!isSelfReference (beanName , candidateName ) && isAutowireCandidate (candidateName , descriptor )) {
1232
- result . put ( candidateName , descriptor . resolveCandidate ( candidateName , requiredType , this ) );
1245
+ addCandidateEntry ( result , candidateName , descriptor , requiredType );
1233
1246
}
1234
1247
}
1235
1248
if (result .isEmpty () && !indicatesMultipleBeans (requiredType )) {
1236
1249
// Consider fallback matches if the first pass failed to find anything...
1237
1250
DependencyDescriptor fallbackDescriptor = descriptor .forFallbackMatch ();
1238
1251
for (String candidateName : candidateNames ) {
1239
1252
if (!isSelfReference (beanName , candidateName ) && isAutowireCandidate (candidateName , fallbackDescriptor )) {
1240
- result . put ( candidateName , descriptor . resolveCandidate ( candidateName , requiredType , this ) );
1253
+ addCandidateEntry ( result , candidateName , descriptor , requiredType );
1241
1254
}
1242
1255
}
1243
1256
if (result .isEmpty ()) {
1244
1257
// Consider self references before as a final pass
1245
1258
for (String candidateName : candidateNames ) {
1246
1259
if (isSelfReference (beanName , candidateName ) && isAutowireCandidate (candidateName , fallbackDescriptor )) {
1247
- result . put ( candidateName , descriptor . resolveCandidate ( candidateName , requiredType , this ) );
1260
+ addCandidateEntry ( result , candidateName , descriptor , requiredType );
1248
1261
}
1249
1262
}
1250
1263
}
1251
1264
}
1252
1265
return result ;
1253
1266
}
1254
1267
1268
+ /**
1269
+ * Add an entry to the candidate map: a bean instance if available or just the resolved
1270
+ * type, preventing early bean initialization ahead of primary candidate selection.
1271
+ */
1272
+ private void addCandidateEntry (Map <String , Object > candidates , String candidateName ,
1273
+ DependencyDescriptor descriptor , Class <?> requiredType ) {
1274
+
1275
+ if (descriptor instanceof MultiElementDependencyDescriptor || containsSingleton (candidateName )) {
1276
+ candidates .put (candidateName , descriptor .resolveCandidate (candidateName , requiredType , this ));
1277
+ }
1278
+ else {
1279
+ candidates .put (candidateName , getType (candidateName ));
1280
+ }
1281
+ }
1282
+
1255
1283
/**
1256
1284
* Determine the autowire candidate in the given set of beans.
1257
1285
* <p>Looks for {@code @Primary} and {@code @Priority} (in that order).
1258
- * @param candidateBeans a Map of candidate names and candidate instances
1286
+ * @param candidates a Map of candidate names and candidate instances
1259
1287
* that match the required type, as returned by {@link #findAutowireCandidates}
1260
1288
* @param descriptor the target dependency to match against
1261
1289
* @return the name of the autowire candidate, or {@code null} if none found
1262
1290
*/
1263
- protected String determineAutowireCandidate (Map <String , Object > candidateBeans , DependencyDescriptor descriptor ) {
1291
+ protected String determineAutowireCandidate (Map <String , Object > candidates , DependencyDescriptor descriptor ) {
1264
1292
Class <?> requiredType = descriptor .getDependencyType ();
1265
- String primaryCandidate = determinePrimaryCandidate (candidateBeans , requiredType );
1293
+ String primaryCandidate = determinePrimaryCandidate (candidates , requiredType );
1266
1294
if (primaryCandidate != null ) {
1267
1295
return primaryCandidate ;
1268
1296
}
1269
- String priorityCandidate = determineHighestPriorityCandidate (candidateBeans , requiredType );
1297
+ String priorityCandidate = determineHighestPriorityCandidate (candidates , requiredType );
1270
1298
if (priorityCandidate != null ) {
1271
1299
return priorityCandidate ;
1272
1300
}
1273
1301
// Fallback
1274
- for (Map .Entry <String , Object > entry : candidateBeans .entrySet ()) {
1275
- String candidateBeanName = entry .getKey ();
1302
+ for (Map .Entry <String , Object > entry : candidates .entrySet ()) {
1303
+ String candidateName = entry .getKey ();
1276
1304
Object beanInstance = entry .getValue ();
1277
1305
if ((beanInstance != null && this .resolvableDependencies .containsValue (beanInstance )) ||
1278
- matchesBeanName (candidateBeanName , descriptor .getDependencyName ())) {
1279
- return candidateBeanName ;
1306
+ matchesBeanName (candidateName , descriptor .getDependencyName ())) {
1307
+ return candidateName ;
1280
1308
}
1281
1309
}
1282
1310
return null ;
1283
1311
}
1284
1312
1285
1313
/**
1286
1314
* Determine the primary candidate in the given set of beans.
1287
- * @param candidateBeans a Map of candidate names and candidate instances
1288
- * that match the required type
1315
+ * @param candidates a Map of candidate names and candidate instances
1316
+ * (or candidate classes if not created yet) that match the required type
1289
1317
* @param requiredType the target dependency type to match against
1290
1318
* @return the name of the primary candidate, or {@code null} if none found
1291
1319
* @see #isPrimary(String, Object)
1292
1320
*/
1293
- protected String determinePrimaryCandidate (Map <String , Object > candidateBeans , Class <?> requiredType ) {
1321
+ protected String determinePrimaryCandidate (Map <String , Object > candidates , Class <?> requiredType ) {
1294
1322
String primaryBeanName = null ;
1295
- for (Map .Entry <String , Object > entry : candidateBeans .entrySet ()) {
1323
+ for (Map .Entry <String , Object > entry : candidates .entrySet ()) {
1296
1324
String candidateBeanName = entry .getKey ();
1297
1325
Object beanInstance = entry .getValue ();
1298
1326
if (isPrimary (candidateBeanName , beanInstance )) {
1299
1327
if (primaryBeanName != null ) {
1300
1328
boolean candidateLocal = containsBeanDefinition (candidateBeanName );
1301
1329
boolean primaryLocal = containsBeanDefinition (primaryBeanName );
1302
1330
if (candidateLocal && primaryLocal ) {
1303
- throw new NoUniqueBeanDefinitionException (requiredType , candidateBeans .size (),
1304
- "more than one 'primary' bean found among candidates: " + candidateBeans .keySet ());
1331
+ throw new NoUniqueBeanDefinitionException (requiredType , candidates .size (),
1332
+ "more than one 'primary' bean found among candidates: " + candidates .keySet ());
1305
1333
}
1306
1334
else if (candidateLocal ) {
1307
1335
primaryBeanName = candidateBeanName ;
@@ -1316,29 +1344,30 @@ else if (candidateLocal) {
1316
1344
}
1317
1345
1318
1346
/**
1319
- * Determine the candidate with the highest priority in the given set of beans. As
1320
- * defined by the {@link org.springframework.core.Ordered} interface, the lowest
1321
- * value has the highest priority.
1322
- * @param candidateBeans a Map of candidate names and candidate instances
1323
- * that match the required type
1347
+ * Determine the candidate with the highest priority in the given set of beans.
1348
+ * <p>Based on {@code @javax.annotation.Priority}. As defined by the related
1349
+ * {@link org.springframework.core.Ordered} interface, the lowest value has
1350
+ * the highest priority.
1351
+ * @param candidates a Map of candidate names and candidate instances
1352
+ * (or candidate classes if not created yet) that match the required type
1324
1353
* @param requiredType the target dependency type to match against
1325
1354
* @return the name of the candidate with the highest priority,
1326
1355
* or {@code null} if none found
1327
1356
* @see #getPriority(Object)
1328
1357
*/
1329
- protected String determineHighestPriorityCandidate (Map <String , Object > candidateBeans , Class <?> requiredType ) {
1358
+ protected String determineHighestPriorityCandidate (Map <String , Object > candidates , Class <?> requiredType ) {
1330
1359
String highestPriorityBeanName = null ;
1331
1360
Integer highestPriority = null ;
1332
- for (Map .Entry <String , Object > entry : candidateBeans .entrySet ()) {
1361
+ for (Map .Entry <String , Object > entry : candidates .entrySet ()) {
1333
1362
String candidateBeanName = entry .getKey ();
1334
1363
Object beanInstance = entry .getValue ();
1335
1364
Integer candidatePriority = getPriority (beanInstance );
1336
1365
if (candidatePriority != null ) {
1337
1366
if (highestPriorityBeanName != null ) {
1338
1367
if (candidatePriority .equals (highestPriority )) {
1339
- throw new NoUniqueBeanDefinitionException (requiredType , candidateBeans .size (),
1340
- "Multiple beans found with the same priority ('" + highestPriority + "') " +
1341
- " among candidates: " + candidateBeans .keySet ());
1368
+ throw new NoUniqueBeanDefinitionException (requiredType , candidates .size (),
1369
+ "Multiple beans found with the same priority ('" + highestPriority +
1370
+ "') among candidates: " + candidates .keySet ());
1342
1371
}
1343
1372
else if (candidatePriority < highestPriority ) {
1344
1373
highestPriorityBeanName = candidateBeanName ;
@@ -1453,7 +1482,7 @@ private void checkBeanNotOfRequiredType(Class<?> type, DependencyDescriptor desc
1453
1482
* Create an {@link Optional} wrapper for the specified dependency.
1454
1483
*/
1455
1484
private Optional <?> createOptionalDependency (DependencyDescriptor descriptor , String beanName , final Object ... args ) {
1456
- DependencyDescriptor descriptorToUse = new DependencyDescriptor (descriptor ) {
1485
+ DependencyDescriptor descriptorToUse = new NestedDependencyDescriptor (descriptor ) {
1457
1486
@ Override
1458
1487
public boolean isRequired () {
1459
1488
return false ;
@@ -1464,7 +1493,6 @@ public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFacto
1464
1493
super .resolveCandidate (beanName , requiredType , beanFactory ));
1465
1494
}
1466
1495
};
1467
- descriptorToUse .increaseNestingLevel ();
1468
1496
return Optional .ofNullable (doResolveDependency (descriptorToUse , beanName , null , null ));
1469
1497
}
1470
1498
@@ -1543,8 +1571,7 @@ private class DependencyObjectProvider implements ObjectProvider<Object>, Serial
1543
1571
private final String beanName ;
1544
1572
1545
1573
public DependencyObjectProvider (DependencyDescriptor descriptor , String beanName ) {
1546
- this .descriptor = new DependencyDescriptor (descriptor );
1547
- this .descriptor .increaseNestingLevel ();
1574
+ this .descriptor = new NestedDependencyDescriptor (descriptor );
1548
1575
this .optional = (this .descriptor .getDependencyType () == Optional .class );
1549
1576
this .beanName = beanName ;
1550
1577
}
@@ -1684,4 +1711,21 @@ private RootBeanDefinition getRootBeanDefinition(String beanName) {
1684
1711
}
1685
1712
}
1686
1713
1714
+
1715
+ private static class NestedDependencyDescriptor extends DependencyDescriptor {
1716
+
1717
+ public NestedDependencyDescriptor (DependencyDescriptor original ) {
1718
+ super (original );
1719
+ increaseNestingLevel ();
1720
+ }
1721
+ }
1722
+
1723
+
1724
+ private static class MultiElementDependencyDescriptor extends NestedDependencyDescriptor {
1725
+
1726
+ public MultiElementDependencyDescriptor (DependencyDescriptor original ) {
1727
+ super (original );
1728
+ }
1729
+ }
1730
+
1687
1731
}
0 commit comments