@@ -986,38 +986,47 @@ public <T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType) throws Bea
986
986
return null ;
987
987
}
988
988
989
+ @ SuppressWarnings ("unchecked" )
989
990
private <T > NamedBeanHolder <T > resolveNamedBean (Class <T > requiredType , Object ... args ) throws BeansException {
990
991
Assert .notNull (requiredType , "Required type must not be null" );
991
- String [] beanNames = getBeanNamesForType (requiredType );
992
+ String [] candidateNames = getBeanNamesForType (requiredType );
992
993
993
- if (beanNames .length > 1 ) {
994
- ArrayList <String > autowireCandidates = new ArrayList <String >();
995
- for (String beanName : beanNames ) {
994
+ if (candidateNames .length > 1 ) {
995
+ List <String > autowireCandidates = new ArrayList <String >(candidateNames . length );
996
+ for (String beanName : candidateNames ) {
996
997
if (!containsBeanDefinition (beanName ) || getBeanDefinition (beanName ).isAutowireCandidate ()) {
997
998
autowireCandidates .add (beanName );
998
999
}
999
1000
}
1000
1001
if (!autowireCandidates .isEmpty ()) {
1001
- beanNames = autowireCandidates .toArray (new String [autowireCandidates .size ()]);
1002
+ candidateNames = autowireCandidates .toArray (new String [autowireCandidates .size ()]);
1002
1003
}
1003
1004
}
1004
1005
1005
- if (beanNames .length == 1 ) {
1006
- String beanName = beanNames [0 ];
1006
+ if (candidateNames .length == 1 ) {
1007
+ String beanName = candidateNames [0 ];
1007
1008
return new NamedBeanHolder <T >(beanName , getBean (beanName , requiredType , args ));
1008
1009
}
1009
- else if (beanNames .length > 1 ) {
1010
- Map <String , Object > candidates = new LinkedHashMap <String , Object >();
1011
- for (String beanName : beanNames ) {
1012
- candidates .put (beanName , getBean (beanName , requiredType , args ));
1010
+ else if (candidateNames .length > 1 ) {
1011
+ Map <String , Object > candidates = new LinkedHashMap <String , Object >(candidateNames .length );
1012
+ for (String candidateName : candidateNames ) {
1013
+ if (containsSingleton (candidateName )) {
1014
+ candidates .put (candidateName , getBean (candidateName , requiredType , args ));
1015
+ }
1016
+ else {
1017
+ candidates .put (candidateName , getType (candidateName ));
1018
+ }
1013
1019
}
1014
- String primaryCandidate = determinePrimaryCandidate (candidates , requiredType );
1015
- if (primaryCandidate ! = null ) {
1016
- return new NamedBeanHolder < T >( primaryCandidate , getBean ( primaryCandidate , requiredType , args ) );
1020
+ String candidateName = determinePrimaryCandidate (candidates , requiredType );
1021
+ if (candidateName = = null ) {
1022
+ candidateName = determineHighestPriorityCandidate ( candidates , requiredType );
1017
1023
}
1018
- String priorityCandidate = determineHighestPriorityCandidate (candidates , requiredType );
1019
- if (priorityCandidate != null ) {
1020
- return new NamedBeanHolder <T >(priorityCandidate , getBean (priorityCandidate , requiredType , args ));
1024
+ if (candidateName != null ) {
1025
+ Object beanInstance = candidates .get (candidateName );
1026
+ if (beanInstance instanceof Class ) {
1027
+ beanInstance = getBean (candidateName , requiredType , args );
1028
+ }
1029
+ return new NamedBeanHolder <T >(candidateName , (T ) beanInstance );
1021
1030
}
1022
1031
throw new NoUniqueBeanDefinitionException (requiredType , candidates .keySet ());
1023
1032
}
@@ -1086,9 +1095,13 @@ public Object doResolveDependency(DependencyDescriptor descriptor, String beanNa
1086
1095
}
1087
1096
return null ;
1088
1097
}
1098
+
1099
+ String autowiredBeanName ;
1100
+ Object instanceCandidate ;
1101
+
1089
1102
if (matchingBeans .size () > 1 ) {
1090
- String primaryBeanName = determineAutowireCandidate (matchingBeans , descriptor );
1091
- if (primaryBeanName == null ) {
1103
+ autowiredBeanName = determineAutowireCandidate (matchingBeans , descriptor );
1104
+ if (autowiredBeanName == null ) {
1092
1105
if (descriptor .isRequired () || !indicatesMultipleBeans (type )) {
1093
1106
return descriptor .resolveNotUnique (type , matchingBeans );
1094
1107
}
@@ -1099,17 +1112,20 @@ public Object doResolveDependency(DependencyDescriptor descriptor, String beanNa
1099
1112
return null ;
1100
1113
}
1101
1114
}
1102
- if (autowiredBeanNames != null ) {
1103
- autowiredBeanNames .add (primaryBeanName );
1104
- }
1105
- return matchingBeans .get (primaryBeanName );
1115
+ instanceCandidate = matchingBeans .get (autowiredBeanName );
1106
1116
}
1107
- // We have exactly one match.
1108
- Map .Entry <String , Object > entry = matchingBeans .entrySet ().iterator ().next ();
1117
+ else {
1118
+ // We have exactly one match.
1119
+ Map .Entry <String , Object > entry = matchingBeans .entrySet ().iterator ().next ();
1120
+ autowiredBeanName = entry .getKey ();
1121
+ instanceCandidate = entry .getValue ();
1122
+ }
1123
+
1109
1124
if (autowiredBeanNames != null ) {
1110
- autowiredBeanNames .add (entry . getKey () );
1125
+ autowiredBeanNames .add (autowiredBeanName );
1111
1126
}
1112
- return entry .getValue ();
1127
+ return (instanceCandidate instanceof Class ?
1128
+ descriptor .resolveCandidate (autowiredBeanName , type , this ) : instanceCandidate );
1113
1129
}
1114
1130
finally {
1115
1131
ConstructorResolver .setCurrentInjectionPoint (previousInjectionPoint );
@@ -1122,9 +1138,8 @@ private Object resolveMultipleBeans(DependencyDescriptor descriptor, String bean
1122
1138
Class <?> type = descriptor .getDependencyType ();
1123
1139
if (type .isArray ()) {
1124
1140
Class <?> componentType = type .getComponentType ();
1125
- DependencyDescriptor targetDesc = new DependencyDescriptor (descriptor );
1126
- targetDesc .increaseNestingLevel ();
1127
- Map <String , Object > matchingBeans = findAutowireCandidates (beanName , componentType , targetDesc );
1141
+ Map <String , Object > matchingBeans = findAutowireCandidates (beanName , componentType ,
1142
+ new MultiElementDependencyDescriptor (descriptor ));
1128
1143
if (matchingBeans .isEmpty ()) {
1129
1144
return null ;
1130
1145
}
@@ -1143,9 +1158,8 @@ else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
1143
1158
if (elementType == null ) {
1144
1159
return null ;
1145
1160
}
1146
- DependencyDescriptor targetDesc = new DependencyDescriptor (descriptor );
1147
- targetDesc .increaseNestingLevel ();
1148
- Map <String , Object > matchingBeans = findAutowireCandidates (beanName , elementType , targetDesc );
1161
+ Map <String , Object > matchingBeans = findAutowireCandidates (beanName , elementType ,
1162
+ new MultiElementDependencyDescriptor (descriptor ));
1149
1163
if (matchingBeans .isEmpty ()) {
1150
1164
return null ;
1151
1165
}
@@ -1168,9 +1182,8 @@ else if (Map.class.isAssignableFrom(type) && type.isInterface()) {
1168
1182
if (valueType == null ) {
1169
1183
return null ;
1170
1184
}
1171
- DependencyDescriptor targetDesc = new DependencyDescriptor (descriptor );
1172
- targetDesc .increaseNestingLevel ();
1173
- Map <String , Object > matchingBeans = findAutowireCandidates (beanName , valueType , targetDesc );
1185
+ Map <String , Object > matchingBeans = findAutowireCandidates (beanName , valueType ,
1186
+ new MultiElementDependencyDescriptor (descriptor ));
1174
1187
if (matchingBeans .isEmpty ()) {
1175
1188
return null ;
1176
1189
}
@@ -1239,79 +1252,94 @@ protected Map<String, Object> findAutowireCandidates(
1239
1252
}
1240
1253
for (String candidateName : candidateNames ) {
1241
1254
if (!isSelfReference (beanName , candidateName ) && isAutowireCandidate (candidateName , descriptor )) {
1242
- result . put ( candidateName , descriptor . resolveCandidate ( candidateName , requiredType , this ) );
1255
+ addCandidateEntry ( result , candidateName , descriptor , requiredType );
1243
1256
}
1244
1257
}
1245
1258
if (result .isEmpty () && !indicatesMultipleBeans (requiredType )) {
1246
1259
// Consider fallback matches if the first pass failed to find anything...
1247
1260
DependencyDescriptor fallbackDescriptor = descriptor .forFallbackMatch ();
1248
1261
for (String candidateName : candidateNames ) {
1249
1262
if (!isSelfReference (beanName , candidateName ) && isAutowireCandidate (candidateName , fallbackDescriptor )) {
1250
- result . put ( candidateName , descriptor . resolveCandidate ( candidateName , requiredType , this ) );
1263
+ addCandidateEntry ( result , candidateName , descriptor , requiredType );
1251
1264
}
1252
1265
}
1253
1266
if (result .isEmpty ()) {
1254
1267
// Consider self references before as a final pass
1255
1268
for (String candidateName : candidateNames ) {
1256
1269
if (isSelfReference (beanName , candidateName ) && isAutowireCandidate (candidateName , fallbackDescriptor )) {
1257
- result . put ( candidateName , descriptor . resolveCandidate ( candidateName , requiredType , this ) );
1270
+ addCandidateEntry ( result , candidateName , descriptor , requiredType );
1258
1271
}
1259
1272
}
1260
1273
}
1261
1274
}
1262
1275
return result ;
1263
1276
}
1264
1277
1278
+ /**
1279
+ * Add an entry to the candidate map: a bean instance if available or just the resolved
1280
+ * type, preventing early bean initialization ahead of primary candidate selection.
1281
+ */
1282
+ private void addCandidateEntry (Map <String , Object > candidates , String candidateName ,
1283
+ DependencyDescriptor descriptor , Class <?> requiredType ) {
1284
+
1285
+ if (descriptor instanceof MultiElementDependencyDescriptor || containsSingleton (candidateName )) {
1286
+ candidates .put (candidateName , descriptor .resolveCandidate (candidateName , requiredType , this ));
1287
+ }
1288
+ else {
1289
+ candidates .put (candidateName , getType (candidateName ));
1290
+ }
1291
+ }
1292
+
1265
1293
/**
1266
1294
* Determine the autowire candidate in the given set of beans.
1267
1295
* <p>Looks for {@code @Primary} and {@code @Priority} (in that order).
1268
- * @param candidateBeans a Map of candidate names and candidate instances
1296
+ * @param candidates a Map of candidate names and candidate instances
1269
1297
* that match the required type, as returned by {@link #findAutowireCandidates}
1270
1298
* @param descriptor the target dependency to match against
1271
1299
* @return the name of the autowire candidate, or {@code null} if none found
1272
1300
*/
1273
- protected String determineAutowireCandidate (Map <String , Object > candidateBeans , DependencyDescriptor descriptor ) {
1301
+ protected String determineAutowireCandidate (Map <String , Object > candidates , DependencyDescriptor descriptor ) {
1274
1302
Class <?> requiredType = descriptor .getDependencyType ();
1275
- String primaryCandidate = determinePrimaryCandidate (candidateBeans , requiredType );
1303
+ String primaryCandidate = determinePrimaryCandidate (candidates , requiredType );
1276
1304
if (primaryCandidate != null ) {
1277
1305
return primaryCandidate ;
1278
1306
}
1279
- String priorityCandidate = determineHighestPriorityCandidate (candidateBeans , requiredType );
1307
+ String priorityCandidate = determineHighestPriorityCandidate (candidates , requiredType );
1280
1308
if (priorityCandidate != null ) {
1281
1309
return priorityCandidate ;
1282
1310
}
1283
1311
// Fallback
1284
- for (Map .Entry <String , Object > entry : candidateBeans .entrySet ()) {
1285
- String candidateBeanName = entry .getKey ();
1312
+ for (Map .Entry <String , Object > entry : candidates .entrySet ()) {
1313
+ String candidateName = entry .getKey ();
1286
1314
Object beanInstance = entry .getValue ();
1287
1315
if ((beanInstance != null && this .resolvableDependencies .containsValue (beanInstance )) ||
1288
- matchesBeanName (candidateBeanName , descriptor .getDependencyName ())) {
1289
- return candidateBeanName ;
1316
+ matchesBeanName (candidateName , descriptor .getDependencyName ())) {
1317
+ return candidateName ;
1290
1318
}
1291
1319
}
1292
1320
return null ;
1293
1321
}
1294
1322
1295
1323
/**
1296
1324
* Determine the primary candidate in the given set of beans.
1297
- * @param candidateBeans a Map of candidate names and candidate instances
1298
- * that match the required type
1325
+ * @param candidates a Map of candidate names and candidate instances
1326
+ * (or candidate classes if not created yet) that match the required type
1299
1327
* @param requiredType the target dependency type to match against
1300
1328
* @return the name of the primary candidate, or {@code null} if none found
1301
1329
* @see #isPrimary(String, Object)
1302
1330
*/
1303
- protected String determinePrimaryCandidate (Map <String , Object > candidateBeans , Class <?> requiredType ) {
1331
+ protected String determinePrimaryCandidate (Map <String , Object > candidates , Class <?> requiredType ) {
1304
1332
String primaryBeanName = null ;
1305
- for (Map .Entry <String , Object > entry : candidateBeans .entrySet ()) {
1333
+ for (Map .Entry <String , Object > entry : candidates .entrySet ()) {
1306
1334
String candidateBeanName = entry .getKey ();
1307
1335
Object beanInstance = entry .getValue ();
1308
1336
if (isPrimary (candidateBeanName , beanInstance )) {
1309
1337
if (primaryBeanName != null ) {
1310
1338
boolean candidateLocal = containsBeanDefinition (candidateBeanName );
1311
1339
boolean primaryLocal = containsBeanDefinition (primaryBeanName );
1312
1340
if (candidateLocal && primaryLocal ) {
1313
- throw new NoUniqueBeanDefinitionException (requiredType , candidateBeans .size (),
1314
- "more than one 'primary' bean found among candidates: " + candidateBeans .keySet ());
1341
+ throw new NoUniqueBeanDefinitionException (requiredType , candidates .size (),
1342
+ "more than one 'primary' bean found among candidates: " + candidates .keySet ());
1315
1343
}
1316
1344
else if (candidateLocal ) {
1317
1345
primaryBeanName = candidateBeanName ;
@@ -1326,29 +1354,30 @@ else if (candidateLocal) {
1326
1354
}
1327
1355
1328
1356
/**
1329
- * Determine the candidate with the highest priority in the given set of beans. As
1330
- * defined by the {@link org.springframework.core.Ordered} interface, the lowest
1331
- * value has the highest priority.
1332
- * @param candidateBeans a Map of candidate names and candidate instances
1333
- * that match the required type
1357
+ * Determine the candidate with the highest priority in the given set of beans.
1358
+ * <p>Based on {@code @javax.annotation.Priority}. As defined by the related
1359
+ * {@link org.springframework.core.Ordered} interface, the lowest value has
1360
+ * the highest priority.
1361
+ * @param candidates a Map of candidate names and candidate instances
1362
+ * (or candidate classes if not created yet) that match the required type
1334
1363
* @param requiredType the target dependency type to match against
1335
1364
* @return the name of the candidate with the highest priority,
1336
1365
* or {@code null} if none found
1337
1366
* @see #getPriority(Object)
1338
1367
*/
1339
- protected String determineHighestPriorityCandidate (Map <String , Object > candidateBeans , Class <?> requiredType ) {
1368
+ protected String determineHighestPriorityCandidate (Map <String , Object > candidates , Class <?> requiredType ) {
1340
1369
String highestPriorityBeanName = null ;
1341
1370
Integer highestPriority = null ;
1342
- for (Map .Entry <String , Object > entry : candidateBeans .entrySet ()) {
1371
+ for (Map .Entry <String , Object > entry : candidates .entrySet ()) {
1343
1372
String candidateBeanName = entry .getKey ();
1344
1373
Object beanInstance = entry .getValue ();
1345
1374
Integer candidatePriority = getPriority (beanInstance );
1346
1375
if (candidatePriority != null ) {
1347
1376
if (highestPriorityBeanName != null ) {
1348
1377
if (candidatePriority .equals (highestPriority )) {
1349
- throw new NoUniqueBeanDefinitionException (requiredType , candidateBeans .size (),
1350
- "Multiple beans found with the same priority ('" + highestPriority + "') " +
1351
- " among candidates: " + candidateBeans .keySet ());
1378
+ throw new NoUniqueBeanDefinitionException (requiredType , candidates .size (),
1379
+ "Multiple beans found with the same priority ('" + highestPriority +
1380
+ "') among candidates: " + candidates .keySet ());
1352
1381
}
1353
1382
else if (candidatePriority < highestPriority ) {
1354
1383
highestPriorityBeanName = candidateBeanName ;
@@ -1529,7 +1558,7 @@ private Object readResolve() {
1529
1558
private class OptionalDependencyFactory {
1530
1559
1531
1560
public Object createOptionalDependency (DependencyDescriptor descriptor , String beanName , final Object ... args ) {
1532
- DependencyDescriptor descriptorToUse = new DependencyDescriptor (descriptor ) {
1561
+ DependencyDescriptor descriptorToUse = new NestedDependencyDescriptor (descriptor ) {
1533
1562
@ Override
1534
1563
public boolean isRequired () {
1535
1564
return false ;
@@ -1540,7 +1569,6 @@ public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFacto
1540
1569
super .resolveCandidate (beanName , requiredType , beanFactory ));
1541
1570
}
1542
1571
};
1543
- descriptorToUse .increaseNestingLevel ();
1544
1572
return Optional .ofNullable (doResolveDependency (descriptorToUse , beanName , null , null ));
1545
1573
}
1546
1574
}
@@ -1558,9 +1586,8 @@ private class DependencyObjectProvider implements ObjectProvider<Object>, Serial
1558
1586
private final String beanName ;
1559
1587
1560
1588
public DependencyObjectProvider (DependencyDescriptor descriptor , String beanName ) {
1561
- this .descriptor = new DependencyDescriptor (descriptor );
1562
- this .descriptor .increaseNestingLevel ();
1563
- this .optional = this .descriptor .getDependencyType ().equals (javaUtilOptionalClass );
1589
+ this .descriptor = new NestedDependencyDescriptor (descriptor );
1590
+ this .optional = (this .descriptor .getDependencyType () == javaUtilOptionalClass );
1564
1591
this .beanName = beanName ;
1565
1592
}
1566
1593
@@ -1676,7 +1703,7 @@ public Object getOrderSource(Object obj) {
1676
1703
if (beanDefinition == null ) {
1677
1704
return null ;
1678
1705
}
1679
- List <Object > sources = new ArrayList <Object >();
1706
+ List <Object > sources = new ArrayList <Object >(2 );
1680
1707
Method factoryMethod = beanDefinition .getResolvedFactoryMethod ();
1681
1708
if (factoryMethod != null ) {
1682
1709
sources .add (factoryMethod );
@@ -1699,4 +1726,21 @@ private RootBeanDefinition getRootBeanDefinition(String beanName) {
1699
1726
}
1700
1727
}
1701
1728
1729
+
1730
+ private static class NestedDependencyDescriptor extends DependencyDescriptor {
1731
+
1732
+ public NestedDependencyDescriptor (DependencyDescriptor original ) {
1733
+ super (original );
1734
+ increaseNestingLevel ();
1735
+ }
1736
+ }
1737
+
1738
+
1739
+ private static class MultiElementDependencyDescriptor extends NestedDependencyDescriptor {
1740
+
1741
+ public MultiElementDependencyDescriptor (DependencyDescriptor original ) {
1742
+ super (original );
1743
+ }
1744
+ }
1745
+
1702
1746
}
0 commit comments