@@ -986,38 +986,47 @@ public <T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType) throws Bea
986986 return null ;
987987 }
988988
989+ @ SuppressWarnings ("unchecked" )
989990 private <T > NamedBeanHolder <T > resolveNamedBean (Class <T > requiredType , Object ... args ) throws BeansException {
990991 Assert .notNull (requiredType , "Required type must not be null" );
991- String [] beanNames = getBeanNamesForType (requiredType );
992+ String [] candidateNames = getBeanNamesForType (requiredType );
992993
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 ) {
996997 if (!containsBeanDefinition (beanName ) || getBeanDefinition (beanName ).isAutowireCandidate ()) {
997998 autowireCandidates .add (beanName );
998999 }
9991000 }
10001001 if (!autowireCandidates .isEmpty ()) {
1001- beanNames = autowireCandidates .toArray (new String [autowireCandidates .size ()]);
1002+ candidateNames = autowireCandidates .toArray (new String [autowireCandidates .size ()]);
10021003 }
10031004 }
10041005
1005- if (beanNames .length == 1 ) {
1006- String beanName = beanNames [0 ];
1006+ if (candidateNames .length == 1 ) {
1007+ String beanName = candidateNames [0 ];
10071008 return new NamedBeanHolder <T >(beanName , getBean (beanName , requiredType , args ));
10081009 }
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+ }
10131019 }
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 );
10171023 }
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 );
10211030 }
10221031 throw new NoUniqueBeanDefinitionException (requiredType , candidates .keySet ());
10231032 }
@@ -1086,9 +1095,13 @@ public Object doResolveDependency(DependencyDescriptor descriptor, String beanNa
10861095 }
10871096 return null ;
10881097 }
1098+
1099+ String autowiredBeanName ;
1100+ Object instanceCandidate ;
1101+
10891102 if (matchingBeans .size () > 1 ) {
1090- String primaryBeanName = determineAutowireCandidate (matchingBeans , descriptor );
1091- if (primaryBeanName == null ) {
1103+ autowiredBeanName = determineAutowireCandidate (matchingBeans , descriptor );
1104+ if (autowiredBeanName == null ) {
10921105 if (descriptor .isRequired () || !indicatesMultipleBeans (type )) {
10931106 return descriptor .resolveNotUnique (type , matchingBeans );
10941107 }
@@ -1099,17 +1112,20 @@ public Object doResolveDependency(DependencyDescriptor descriptor, String beanNa
10991112 return null ;
11001113 }
11011114 }
1102- if (autowiredBeanNames != null ) {
1103- autowiredBeanNames .add (primaryBeanName );
1104- }
1105- return matchingBeans .get (primaryBeanName );
1115+ instanceCandidate = matchingBeans .get (autowiredBeanName );
11061116 }
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+
11091124 if (autowiredBeanNames != null ) {
1110- autowiredBeanNames .add (entry . getKey () );
1125+ autowiredBeanNames .add (autowiredBeanName );
11111126 }
1112- return entry .getValue ();
1127+ return (instanceCandidate instanceof Class ?
1128+ descriptor .resolveCandidate (autowiredBeanName , type , this ) : instanceCandidate );
11131129 }
11141130 finally {
11151131 ConstructorResolver .setCurrentInjectionPoint (previousInjectionPoint );
@@ -1122,9 +1138,8 @@ private Object resolveMultipleBeans(DependencyDescriptor descriptor, String bean
11221138 Class <?> type = descriptor .getDependencyType ();
11231139 if (type .isArray ()) {
11241140 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 ));
11281143 if (matchingBeans .isEmpty ()) {
11291144 return null ;
11301145 }
@@ -1143,9 +1158,8 @@ else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
11431158 if (elementType == null ) {
11441159 return null ;
11451160 }
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 ));
11491163 if (matchingBeans .isEmpty ()) {
11501164 return null ;
11511165 }
@@ -1168,9 +1182,8 @@ else if (Map.class.isAssignableFrom(type) && type.isInterface()) {
11681182 if (valueType == null ) {
11691183 return null ;
11701184 }
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 ));
11741187 if (matchingBeans .isEmpty ()) {
11751188 return null ;
11761189 }
@@ -1239,79 +1252,94 @@ protected Map<String, Object> findAutowireCandidates(
12391252 }
12401253 for (String candidateName : candidateNames ) {
12411254 if (!isSelfReference (beanName , candidateName ) && isAutowireCandidate (candidateName , descriptor )) {
1242- result . put ( candidateName , descriptor . resolveCandidate ( candidateName , requiredType , this ) );
1255+ addCandidateEntry ( result , candidateName , descriptor , requiredType );
12431256 }
12441257 }
12451258 if (result .isEmpty () && !indicatesMultipleBeans (requiredType )) {
12461259 // Consider fallback matches if the first pass failed to find anything...
12471260 DependencyDescriptor fallbackDescriptor = descriptor .forFallbackMatch ();
12481261 for (String candidateName : candidateNames ) {
12491262 if (!isSelfReference (beanName , candidateName ) && isAutowireCandidate (candidateName , fallbackDescriptor )) {
1250- result . put ( candidateName , descriptor . resolveCandidate ( candidateName , requiredType , this ) );
1263+ addCandidateEntry ( result , candidateName , descriptor , requiredType );
12511264 }
12521265 }
12531266 if (result .isEmpty ()) {
12541267 // Consider self references before as a final pass
12551268 for (String candidateName : candidateNames ) {
12561269 if (isSelfReference (beanName , candidateName ) && isAutowireCandidate (candidateName , fallbackDescriptor )) {
1257- result . put ( candidateName , descriptor . resolveCandidate ( candidateName , requiredType , this ) );
1270+ addCandidateEntry ( result , candidateName , descriptor , requiredType );
12581271 }
12591272 }
12601273 }
12611274 }
12621275 return result ;
12631276 }
12641277
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+
12651293 /**
12661294 * Determine the autowire candidate in the given set of beans.
12671295 * <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
12691297 * that match the required type, as returned by {@link #findAutowireCandidates}
12701298 * @param descriptor the target dependency to match against
12711299 * @return the name of the autowire candidate, or {@code null} if none found
12721300 */
1273- protected String determineAutowireCandidate (Map <String , Object > candidateBeans , DependencyDescriptor descriptor ) {
1301+ protected String determineAutowireCandidate (Map <String , Object > candidates , DependencyDescriptor descriptor ) {
12741302 Class <?> requiredType = descriptor .getDependencyType ();
1275- String primaryCandidate = determinePrimaryCandidate (candidateBeans , requiredType );
1303+ String primaryCandidate = determinePrimaryCandidate (candidates , requiredType );
12761304 if (primaryCandidate != null ) {
12771305 return primaryCandidate ;
12781306 }
1279- String priorityCandidate = determineHighestPriorityCandidate (candidateBeans , requiredType );
1307+ String priorityCandidate = determineHighestPriorityCandidate (candidates , requiredType );
12801308 if (priorityCandidate != null ) {
12811309 return priorityCandidate ;
12821310 }
12831311 // 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 ();
12861314 Object beanInstance = entry .getValue ();
12871315 if ((beanInstance != null && this .resolvableDependencies .containsValue (beanInstance )) ||
1288- matchesBeanName (candidateBeanName , descriptor .getDependencyName ())) {
1289- return candidateBeanName ;
1316+ matchesBeanName (candidateName , descriptor .getDependencyName ())) {
1317+ return candidateName ;
12901318 }
12911319 }
12921320 return null ;
12931321 }
12941322
12951323 /**
12961324 * 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
12991327 * @param requiredType the target dependency type to match against
13001328 * @return the name of the primary candidate, or {@code null} if none found
13011329 * @see #isPrimary(String, Object)
13021330 */
1303- protected String determinePrimaryCandidate (Map <String , Object > candidateBeans , Class <?> requiredType ) {
1331+ protected String determinePrimaryCandidate (Map <String , Object > candidates , Class <?> requiredType ) {
13041332 String primaryBeanName = null ;
1305- for (Map .Entry <String , Object > entry : candidateBeans .entrySet ()) {
1333+ for (Map .Entry <String , Object > entry : candidates .entrySet ()) {
13061334 String candidateBeanName = entry .getKey ();
13071335 Object beanInstance = entry .getValue ();
13081336 if (isPrimary (candidateBeanName , beanInstance )) {
13091337 if (primaryBeanName != null ) {
13101338 boolean candidateLocal = containsBeanDefinition (candidateBeanName );
13111339 boolean primaryLocal = containsBeanDefinition (primaryBeanName );
13121340 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 ());
13151343 }
13161344 else if (candidateLocal ) {
13171345 primaryBeanName = candidateBeanName ;
@@ -1326,29 +1354,30 @@ else if (candidateLocal) {
13261354 }
13271355
13281356 /**
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
13341363 * @param requiredType the target dependency type to match against
13351364 * @return the name of the candidate with the highest priority,
13361365 * or {@code null} if none found
13371366 * @see #getPriority(Object)
13381367 */
1339- protected String determineHighestPriorityCandidate (Map <String , Object > candidateBeans , Class <?> requiredType ) {
1368+ protected String determineHighestPriorityCandidate (Map <String , Object > candidates , Class <?> requiredType ) {
13401369 String highestPriorityBeanName = null ;
13411370 Integer highestPriority = null ;
1342- for (Map .Entry <String , Object > entry : candidateBeans .entrySet ()) {
1371+ for (Map .Entry <String , Object > entry : candidates .entrySet ()) {
13431372 String candidateBeanName = entry .getKey ();
13441373 Object beanInstance = entry .getValue ();
13451374 Integer candidatePriority = getPriority (beanInstance );
13461375 if (candidatePriority != null ) {
13471376 if (highestPriorityBeanName != null ) {
13481377 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 ());
13521381 }
13531382 else if (candidatePriority < highestPriority ) {
13541383 highestPriorityBeanName = candidateBeanName ;
@@ -1529,7 +1558,7 @@ private Object readResolve() {
15291558 private class OptionalDependencyFactory {
15301559
15311560 public Object createOptionalDependency (DependencyDescriptor descriptor , String beanName , final Object ... args ) {
1532- DependencyDescriptor descriptorToUse = new DependencyDescriptor (descriptor ) {
1561+ DependencyDescriptor descriptorToUse = new NestedDependencyDescriptor (descriptor ) {
15331562 @ Override
15341563 public boolean isRequired () {
15351564 return false ;
@@ -1540,7 +1569,6 @@ public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFacto
15401569 super .resolveCandidate (beanName , requiredType , beanFactory ));
15411570 }
15421571 };
1543- descriptorToUse .increaseNestingLevel ();
15441572 return Optional .ofNullable (doResolveDependency (descriptorToUse , beanName , null , null ));
15451573 }
15461574 }
@@ -1558,9 +1586,8 @@ private class DependencyObjectProvider implements ObjectProvider<Object>, Serial
15581586 private final String beanName ;
15591587
15601588 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 );
15641591 this .beanName = beanName ;
15651592 }
15661593
@@ -1676,7 +1703,7 @@ public Object getOrderSource(Object obj) {
16761703 if (beanDefinition == null ) {
16771704 return null ;
16781705 }
1679- List <Object > sources = new ArrayList <Object >();
1706+ List <Object > sources = new ArrayList <Object >(2 );
16801707 Method factoryMethod = beanDefinition .getResolvedFactoryMethod ();
16811708 if (factoryMethod != null ) {
16821709 sources .add (factoryMethod );
@@ -1699,4 +1726,21 @@ private RootBeanDefinition getRootBeanDefinition(String beanName) {
16991726 }
17001727 }
17011728
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+
17021746}
0 commit comments