@@ -976,38 +976,47 @@ public <T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType) throws Bea
976976 return null ;
977977 }
978978
979+ @ SuppressWarnings ("unchecked" )
979980 private <T > NamedBeanHolder <T > resolveNamedBean (Class <T > requiredType , Object ... args ) throws BeansException {
980981 Assert .notNull (requiredType , "Required type must not be null" );
981- String [] beanNames = getBeanNamesForType (requiredType );
982+ String [] candidateNames = getBeanNamesForType (requiredType );
982983
983- if (beanNames .length > 1 ) {
984+ if (candidateNames .length > 1 ) {
984985 ArrayList <String > autowireCandidates = new ArrayList <>();
985- for (String beanName : beanNames ) {
986+ for (String beanName : candidateNames ) {
986987 if (!containsBeanDefinition (beanName ) || getBeanDefinition (beanName ).isAutowireCandidate ()) {
987988 autowireCandidates .add (beanName );
988989 }
989990 }
990991 if (!autowireCandidates .isEmpty ()) {
991- beanNames = autowireCandidates .toArray (new String [autowireCandidates .size ()]);
992+ candidateNames = autowireCandidates .toArray (new String [autowireCandidates .size ()]);
992993 }
993994 }
994995
995- if (beanNames .length == 1 ) {
996- String beanName = beanNames [0 ];
996+ if (candidateNames .length == 1 ) {
997+ String beanName = candidateNames [0 ];
997998 return new NamedBeanHolder <>(beanName , getBean (beanName , requiredType , args ));
998999 }
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+ }
10031009 }
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 );
10071013 }
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 );
10111020 }
10121021 throw new NoUniqueBeanDefinitionException (requiredType , candidates .keySet ());
10131022 }
@@ -1076,9 +1085,13 @@ public Object doResolveDependency(DependencyDescriptor descriptor, String beanNa
10761085 }
10771086 return null ;
10781087 }
1088+
1089+ String autowiredBeanName ;
1090+ Object instanceCandidate ;
1091+
10791092 if (matchingBeans .size () > 1 ) {
1080- String primaryBeanName = determineAutowireCandidate (matchingBeans , descriptor );
1081- if (primaryBeanName == null ) {
1093+ autowiredBeanName = determineAutowireCandidate (matchingBeans , descriptor );
1094+ if (autowiredBeanName == null ) {
10821095 if (descriptor .isRequired () || !indicatesMultipleBeans (type )) {
10831096 return descriptor .resolveNotUnique (type , matchingBeans );
10841097 }
@@ -1089,17 +1102,20 @@ public Object doResolveDependency(DependencyDescriptor descriptor, String beanNa
10891102 return null ;
10901103 }
10911104 }
1092- if (autowiredBeanNames != null ) {
1093- autowiredBeanNames .add (primaryBeanName );
1094- }
1095- return matchingBeans .get (primaryBeanName );
1105+ instanceCandidate = matchingBeans .get (autowiredBeanName );
10961106 }
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+
10991114 if (autowiredBeanNames != null ) {
1100- autowiredBeanNames .add (entry . getKey () );
1115+ autowiredBeanNames .add (autowiredBeanName );
11011116 }
1102- return entry .getValue ();
1117+ return (instanceCandidate instanceof Class ?
1118+ descriptor .resolveCandidate (autowiredBeanName , type , this ) : instanceCandidate );
11031119 }
11041120 finally {
11051121 ConstructorResolver .setCurrentInjectionPoint (previousInjectionPoint );
@@ -1112,9 +1128,8 @@ private Object resolveMultipleBeans(DependencyDescriptor descriptor, String bean
11121128 Class <?> type = descriptor .getDependencyType ();
11131129 if (type .isArray ()) {
11141130 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 ));
11181133 if (matchingBeans .isEmpty ()) {
11191134 return null ;
11201135 }
@@ -1133,9 +1148,8 @@ else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
11331148 if (elementType == null ) {
11341149 return null ;
11351150 }
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 ));
11391153 if (matchingBeans .isEmpty ()) {
11401154 return null ;
11411155 }
@@ -1158,9 +1172,8 @@ else if (Map.class.isAssignableFrom(type) && type.isInterface()) {
11581172 if (valueType == null ) {
11591173 return null ;
11601174 }
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 ));
11641177 if (matchingBeans .isEmpty ()) {
11651178 return null ;
11661179 }
@@ -1229,79 +1242,94 @@ protected Map<String, Object> findAutowireCandidates(
12291242 }
12301243 for (String candidateName : candidateNames ) {
12311244 if (!isSelfReference (beanName , candidateName ) && isAutowireCandidate (candidateName , descriptor )) {
1232- result . put ( candidateName , descriptor . resolveCandidate ( candidateName , requiredType , this ) );
1245+ addCandidateEntry ( result , candidateName , descriptor , requiredType );
12331246 }
12341247 }
12351248 if (result .isEmpty () && !indicatesMultipleBeans (requiredType )) {
12361249 // Consider fallback matches if the first pass failed to find anything...
12371250 DependencyDescriptor fallbackDescriptor = descriptor .forFallbackMatch ();
12381251 for (String candidateName : candidateNames ) {
12391252 if (!isSelfReference (beanName , candidateName ) && isAutowireCandidate (candidateName , fallbackDescriptor )) {
1240- result . put ( candidateName , descriptor . resolveCandidate ( candidateName , requiredType , this ) );
1253+ addCandidateEntry ( result , candidateName , descriptor , requiredType );
12411254 }
12421255 }
12431256 if (result .isEmpty ()) {
12441257 // Consider self references before as a final pass
12451258 for (String candidateName : candidateNames ) {
12461259 if (isSelfReference (beanName , candidateName ) && isAutowireCandidate (candidateName , fallbackDescriptor )) {
1247- result . put ( candidateName , descriptor . resolveCandidate ( candidateName , requiredType , this ) );
1260+ addCandidateEntry ( result , candidateName , descriptor , requiredType );
12481261 }
12491262 }
12501263 }
12511264 }
12521265 return result ;
12531266 }
12541267
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+
12551283 /**
12561284 * Determine the autowire candidate in the given set of beans.
12571285 * <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
12591287 * that match the required type, as returned by {@link #findAutowireCandidates}
12601288 * @param descriptor the target dependency to match against
12611289 * @return the name of the autowire candidate, or {@code null} if none found
12621290 */
1263- protected String determineAutowireCandidate (Map <String , Object > candidateBeans , DependencyDescriptor descriptor ) {
1291+ protected String determineAutowireCandidate (Map <String , Object > candidates , DependencyDescriptor descriptor ) {
12641292 Class <?> requiredType = descriptor .getDependencyType ();
1265- String primaryCandidate = determinePrimaryCandidate (candidateBeans , requiredType );
1293+ String primaryCandidate = determinePrimaryCandidate (candidates , requiredType );
12661294 if (primaryCandidate != null ) {
12671295 return primaryCandidate ;
12681296 }
1269- String priorityCandidate = determineHighestPriorityCandidate (candidateBeans , requiredType );
1297+ String priorityCandidate = determineHighestPriorityCandidate (candidates , requiredType );
12701298 if (priorityCandidate != null ) {
12711299 return priorityCandidate ;
12721300 }
12731301 // 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 ();
12761304 Object beanInstance = entry .getValue ();
12771305 if ((beanInstance != null && this .resolvableDependencies .containsValue (beanInstance )) ||
1278- matchesBeanName (candidateBeanName , descriptor .getDependencyName ())) {
1279- return candidateBeanName ;
1306+ matchesBeanName (candidateName , descriptor .getDependencyName ())) {
1307+ return candidateName ;
12801308 }
12811309 }
12821310 return null ;
12831311 }
12841312
12851313 /**
12861314 * 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
12891317 * @param requiredType the target dependency type to match against
12901318 * @return the name of the primary candidate, or {@code null} if none found
12911319 * @see #isPrimary(String, Object)
12921320 */
1293- protected String determinePrimaryCandidate (Map <String , Object > candidateBeans , Class <?> requiredType ) {
1321+ protected String determinePrimaryCandidate (Map <String , Object > candidates , Class <?> requiredType ) {
12941322 String primaryBeanName = null ;
1295- for (Map .Entry <String , Object > entry : candidateBeans .entrySet ()) {
1323+ for (Map .Entry <String , Object > entry : candidates .entrySet ()) {
12961324 String candidateBeanName = entry .getKey ();
12971325 Object beanInstance = entry .getValue ();
12981326 if (isPrimary (candidateBeanName , beanInstance )) {
12991327 if (primaryBeanName != null ) {
13001328 boolean candidateLocal = containsBeanDefinition (candidateBeanName );
13011329 boolean primaryLocal = containsBeanDefinition (primaryBeanName );
13021330 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 ());
13051333 }
13061334 else if (candidateLocal ) {
13071335 primaryBeanName = candidateBeanName ;
@@ -1316,29 +1344,30 @@ else if (candidateLocal) {
13161344 }
13171345
13181346 /**
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
13241353 * @param requiredType the target dependency type to match against
13251354 * @return the name of the candidate with the highest priority,
13261355 * or {@code null} if none found
13271356 * @see #getPriority(Object)
13281357 */
1329- protected String determineHighestPriorityCandidate (Map <String , Object > candidateBeans , Class <?> requiredType ) {
1358+ protected String determineHighestPriorityCandidate (Map <String , Object > candidates , Class <?> requiredType ) {
13301359 String highestPriorityBeanName = null ;
13311360 Integer highestPriority = null ;
1332- for (Map .Entry <String , Object > entry : candidateBeans .entrySet ()) {
1361+ for (Map .Entry <String , Object > entry : candidates .entrySet ()) {
13331362 String candidateBeanName = entry .getKey ();
13341363 Object beanInstance = entry .getValue ();
13351364 Integer candidatePriority = getPriority (beanInstance );
13361365 if (candidatePriority != null ) {
13371366 if (highestPriorityBeanName != null ) {
13381367 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 ());
13421371 }
13431372 else if (candidatePriority < highestPriority ) {
13441373 highestPriorityBeanName = candidateBeanName ;
@@ -1453,7 +1482,7 @@ private void checkBeanNotOfRequiredType(Class<?> type, DependencyDescriptor desc
14531482 * Create an {@link Optional} wrapper for the specified dependency.
14541483 */
14551484 private Optional <?> createOptionalDependency (DependencyDescriptor descriptor , String beanName , final Object ... args ) {
1456- DependencyDescriptor descriptorToUse = new DependencyDescriptor (descriptor ) {
1485+ DependencyDescriptor descriptorToUse = new NestedDependencyDescriptor (descriptor ) {
14571486 @ Override
14581487 public boolean isRequired () {
14591488 return false ;
@@ -1464,7 +1493,6 @@ public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFacto
14641493 super .resolveCandidate (beanName , requiredType , beanFactory ));
14651494 }
14661495 };
1467- descriptorToUse .increaseNestingLevel ();
14681496 return Optional .ofNullable (doResolveDependency (descriptorToUse , beanName , null , null ));
14691497 }
14701498
@@ -1543,8 +1571,7 @@ private class DependencyObjectProvider implements ObjectProvider<Object>, Serial
15431571 private final String beanName ;
15441572
15451573 public DependencyObjectProvider (DependencyDescriptor descriptor , String beanName ) {
1546- this .descriptor = new DependencyDescriptor (descriptor );
1547- this .descriptor .increaseNestingLevel ();
1574+ this .descriptor = new NestedDependencyDescriptor (descriptor );
15481575 this .optional = (this .descriptor .getDependencyType () == Optional .class );
15491576 this .beanName = beanName ;
15501577 }
@@ -1684,4 +1711,21 @@ private RootBeanDefinition getRootBeanDefinition(String beanName) {
16841711 }
16851712 }
16861713
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+
16871731}
0 commit comments