DefaultListableBeanFactory does not trigger early candidate creation ahead of primary bean selection
Issue: SPR-14611
(cherry picked from commit c4fcdb6)
			
			
This commit is contained in:
		
							parent
							
								
									74bf659c56
								
							
						
					
					
						commit
						a7849b2861
					
				| 
						 | 
					@ -986,38 +986,47 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
 | 
				
			||||||
		return null;
 | 
							return null;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@SuppressWarnings("unchecked")
 | 
				
			||||||
	private <T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType, Object... args) throws BeansException {
 | 
						private <T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType, Object... args) throws BeansException {
 | 
				
			||||||
		Assert.notNull(requiredType, "Required type must not be null");
 | 
							Assert.notNull(requiredType, "Required type must not be null");
 | 
				
			||||||
		String[] beanNames = getBeanNamesForType(requiredType);
 | 
							String[] candidateNames = getBeanNamesForType(requiredType);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (beanNames.length > 1) {
 | 
							if (candidateNames.length > 1) {
 | 
				
			||||||
			ArrayList<String> autowireCandidates = new ArrayList<String>();
 | 
								List<String> autowireCandidates = new ArrayList<String>(candidateNames.length);
 | 
				
			||||||
			for (String beanName : beanNames) {
 | 
								for (String beanName : candidateNames) {
 | 
				
			||||||
				if (!containsBeanDefinition(beanName) || getBeanDefinition(beanName).isAutowireCandidate()) {
 | 
									if (!containsBeanDefinition(beanName) || getBeanDefinition(beanName).isAutowireCandidate()) {
 | 
				
			||||||
					autowireCandidates.add(beanName);
 | 
										autowireCandidates.add(beanName);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if (!autowireCandidates.isEmpty()) {
 | 
								if (!autowireCandidates.isEmpty()) {
 | 
				
			||||||
				beanNames = autowireCandidates.toArray(new String[autowireCandidates.size()]);
 | 
									candidateNames = autowireCandidates.toArray(new String[autowireCandidates.size()]);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (beanNames.length == 1) {
 | 
							if (candidateNames.length == 1) {
 | 
				
			||||||
			String beanName = beanNames[0];
 | 
								String beanName = candidateNames[0];
 | 
				
			||||||
			return new NamedBeanHolder<T>(beanName, getBean(beanName, requiredType, args));
 | 
								return new NamedBeanHolder<T>(beanName, getBean(beanName, requiredType, args));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else if (beanNames.length > 1) {
 | 
							else if (candidateNames.length > 1) {
 | 
				
			||||||
			Map<String, Object> candidates = new LinkedHashMap<String, Object>();
 | 
								Map<String, Object> candidates = new LinkedHashMap<String, Object>(candidateNames.length);
 | 
				
			||||||
			for (String beanName : beanNames) {
 | 
								for (String candidateName : candidateNames) {
 | 
				
			||||||
				candidates.put(beanName, getBean(beanName, requiredType, args));
 | 
									if (containsSingleton(candidateName)) {
 | 
				
			||||||
 | 
										candidates.put(candidateName, getBean(candidateName, requiredType, args));
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									else {
 | 
				
			||||||
 | 
										candidates.put(candidateName, getType(candidateName));
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
 | 
								String candidateName = determinePrimaryCandidate(candidates, requiredType);
 | 
				
			||||||
			if (primaryCandidate != null) {
 | 
								if (candidateName == null) {
 | 
				
			||||||
				return new NamedBeanHolder<T>(primaryCandidate, getBean(primaryCandidate, requiredType, args));
 | 
									candidateName = determineHighestPriorityCandidate(candidates, requiredType);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
 | 
								if (candidateName != null) {
 | 
				
			||||||
			if (priorityCandidate != null) {
 | 
									Object beanInstance = candidates.get(candidateName);
 | 
				
			||||||
				return new NamedBeanHolder<T>(priorityCandidate, getBean(priorityCandidate, requiredType, args));
 | 
									if (beanInstance instanceof Class) {
 | 
				
			||||||
 | 
										beanInstance = getBean(candidateName, requiredType, args);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									return new NamedBeanHolder<T>(candidateName, (T) beanInstance);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet());
 | 
								throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet());
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -1086,9 +1095,13 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				return null;
 | 
									return null;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								String autowiredBeanName;
 | 
				
			||||||
 | 
								Object instanceCandidate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (matchingBeans.size() > 1) {
 | 
								if (matchingBeans.size() > 1) {
 | 
				
			||||||
				String primaryBeanName = determineAutowireCandidate(matchingBeans, descriptor);
 | 
									autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
 | 
				
			||||||
				if (primaryBeanName == null) {
 | 
									if (autowiredBeanName == null) {
 | 
				
			||||||
					if (descriptor.isRequired() || !indicatesMultipleBeans(type)) {
 | 
										if (descriptor.isRequired() || !indicatesMultipleBeans(type)) {
 | 
				
			||||||
						return descriptor.resolveNotUnique(type, matchingBeans);
 | 
											return descriptor.resolveNotUnique(type, matchingBeans);
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
| 
						 | 
					@ -1099,17 +1112,20 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
 | 
				
			||||||
						return null;
 | 
											return null;
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				if (autowiredBeanNames != null) {
 | 
									instanceCandidate = matchingBeans.get(autowiredBeanName);
 | 
				
			||||||
					autowiredBeanNames.add(primaryBeanName);
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				return matchingBeans.get(primaryBeanName);
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			// We have exactly one match.
 | 
								else {
 | 
				
			||||||
			Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
 | 
									// We have exactly one match.
 | 
				
			||||||
 | 
									Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
 | 
				
			||||||
 | 
									autowiredBeanName = entry.getKey();
 | 
				
			||||||
 | 
									instanceCandidate = entry.getValue();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (autowiredBeanNames != null) {
 | 
								if (autowiredBeanNames != null) {
 | 
				
			||||||
				autowiredBeanNames.add(entry.getKey());
 | 
									autowiredBeanNames.add(autowiredBeanName);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return entry.getValue();
 | 
								return (instanceCandidate instanceof Class ?
 | 
				
			||||||
 | 
										descriptor.resolveCandidate(autowiredBeanName, type, this) : instanceCandidate);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		finally {
 | 
							finally {
 | 
				
			||||||
			ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
 | 
								ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
 | 
				
			||||||
| 
						 | 
					@ -1122,9 +1138,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
 | 
				
			||||||
		Class<?> type = descriptor.getDependencyType();
 | 
							Class<?> type = descriptor.getDependencyType();
 | 
				
			||||||
		if (type.isArray()) {
 | 
							if (type.isArray()) {
 | 
				
			||||||
			Class<?> componentType = type.getComponentType();
 | 
								Class<?> componentType = type.getComponentType();
 | 
				
			||||||
			DependencyDescriptor targetDesc = new DependencyDescriptor(descriptor);
 | 
								Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType,
 | 
				
			||||||
			targetDesc.increaseNestingLevel();
 | 
										new MultiElementDependencyDescriptor(descriptor));
 | 
				
			||||||
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType, targetDesc);
 | 
					 | 
				
			||||||
			if (matchingBeans.isEmpty()) {
 | 
								if (matchingBeans.isEmpty()) {
 | 
				
			||||||
				return null;
 | 
									return null;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -1143,9 +1158,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
 | 
				
			||||||
			if (elementType == null) {
 | 
								if (elementType == null) {
 | 
				
			||||||
				return null;
 | 
									return null;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			DependencyDescriptor targetDesc = new DependencyDescriptor(descriptor);
 | 
								Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,
 | 
				
			||||||
			targetDesc.increaseNestingLevel();
 | 
										new MultiElementDependencyDescriptor(descriptor));
 | 
				
			||||||
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType, targetDesc);
 | 
					 | 
				
			||||||
			if (matchingBeans.isEmpty()) {
 | 
								if (matchingBeans.isEmpty()) {
 | 
				
			||||||
				return null;
 | 
									return null;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -1168,9 +1182,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
 | 
				
			||||||
			if (valueType == null) {
 | 
								if (valueType == null) {
 | 
				
			||||||
				return null;
 | 
									return null;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			DependencyDescriptor targetDesc = new DependencyDescriptor(descriptor);
 | 
								Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType,
 | 
				
			||||||
			targetDesc.increaseNestingLevel();
 | 
										new MultiElementDependencyDescriptor(descriptor));
 | 
				
			||||||
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType, targetDesc);
 | 
					 | 
				
			||||||
			if (matchingBeans.isEmpty()) {
 | 
								if (matchingBeans.isEmpty()) {
 | 
				
			||||||
				return null;
 | 
									return null;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -1239,7 +1252,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		for (String candidateName : candidateNames) {
 | 
							for (String candidateName : candidateNames) {
 | 
				
			||||||
			if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, descriptor)) {
 | 
								if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, descriptor)) {
 | 
				
			||||||
				result.put(candidateName, descriptor.resolveCandidate(candidateName, requiredType, this));
 | 
									addCandidateEntry(result, candidateName, descriptor, requiredType);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (result.isEmpty() && !indicatesMultipleBeans(requiredType)) {
 | 
							if (result.isEmpty() && !indicatesMultipleBeans(requiredType)) {
 | 
				
			||||||
| 
						 | 
					@ -1247,14 +1260,14 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
 | 
				
			||||||
			DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
 | 
								DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
 | 
				
			||||||
			for (String candidateName : candidateNames) {
 | 
								for (String candidateName : candidateNames) {
 | 
				
			||||||
				if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, fallbackDescriptor)) {
 | 
									if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, fallbackDescriptor)) {
 | 
				
			||||||
					result.put(candidateName, descriptor.resolveCandidate(candidateName, requiredType, this));
 | 
										addCandidateEntry(result, candidateName, descriptor, requiredType);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if (result.isEmpty()) {
 | 
								if (result.isEmpty()) {
 | 
				
			||||||
				// Consider self references before as a final pass
 | 
									// Consider self references before as a final pass
 | 
				
			||||||
				for (String candidateName : candidateNames) {
 | 
									for (String candidateName : candidateNames) {
 | 
				
			||||||
					if (isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, fallbackDescriptor)) {
 | 
										if (isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, fallbackDescriptor)) {
 | 
				
			||||||
						result.put(candidateName, descriptor.resolveCandidate(candidateName, requiredType, this));
 | 
											addCandidateEntry(result, candidateName, descriptor, requiredType);
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -1262,31 +1275,46 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
 | 
				
			||||||
		return result;
 | 
							return result;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Add an entry to the candidate map: a bean instance if available or just the resolved
 | 
				
			||||||
 | 
						 * type, preventing early bean initialization ahead of primary candidate selection.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						private void addCandidateEntry(Map<String, Object> candidates, String candidateName,
 | 
				
			||||||
 | 
								DependencyDescriptor descriptor, Class<?> requiredType) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (descriptor instanceof MultiElementDependencyDescriptor || containsSingleton(candidateName)) {
 | 
				
			||||||
 | 
								candidates.put(candidateName, descriptor.resolveCandidate(candidateName, requiredType, this));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								candidates.put(candidateName, getType(candidateName));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Determine the autowire candidate in the given set of beans.
 | 
						 * Determine the autowire candidate in the given set of beans.
 | 
				
			||||||
	 * <p>Looks for {@code @Primary} and {@code @Priority} (in that order).
 | 
						 * <p>Looks for {@code @Primary} and {@code @Priority} (in that order).
 | 
				
			||||||
	 * @param candidateBeans a Map of candidate names and candidate instances
 | 
						 * @param candidates a Map of candidate names and candidate instances
 | 
				
			||||||
	 * that match the required type, as returned by {@link #findAutowireCandidates}
 | 
						 * that match the required type, as returned by {@link #findAutowireCandidates}
 | 
				
			||||||
	 * @param descriptor the target dependency to match against
 | 
						 * @param descriptor the target dependency to match against
 | 
				
			||||||
	 * @return the name of the autowire candidate, or {@code null} if none found
 | 
						 * @return the name of the autowire candidate, or {@code null} if none found
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	protected String determineAutowireCandidate(Map<String, Object> candidateBeans, DependencyDescriptor descriptor) {
 | 
						protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
 | 
				
			||||||
		Class<?> requiredType = descriptor.getDependencyType();
 | 
							Class<?> requiredType = descriptor.getDependencyType();
 | 
				
			||||||
		String primaryCandidate = determinePrimaryCandidate(candidateBeans, requiredType);
 | 
							String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
 | 
				
			||||||
		if (primaryCandidate != null) {
 | 
							if (primaryCandidate != null) {
 | 
				
			||||||
			return primaryCandidate;
 | 
								return primaryCandidate;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		String priorityCandidate = determineHighestPriorityCandidate(candidateBeans, requiredType);
 | 
							String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
 | 
				
			||||||
		if (priorityCandidate != null) {
 | 
							if (priorityCandidate != null) {
 | 
				
			||||||
			return priorityCandidate;
 | 
								return priorityCandidate;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// Fallback
 | 
							// Fallback
 | 
				
			||||||
		for (Map.Entry<String, Object> entry : candidateBeans.entrySet()) {
 | 
							for (Map.Entry<String, Object> entry : candidates.entrySet()) {
 | 
				
			||||||
			String candidateBeanName = entry.getKey();
 | 
								String candidateName = entry.getKey();
 | 
				
			||||||
			Object beanInstance = entry.getValue();
 | 
								Object beanInstance = entry.getValue();
 | 
				
			||||||
			if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||
 | 
								if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||
 | 
				
			||||||
					matchesBeanName(candidateBeanName, descriptor.getDependencyName())) {
 | 
										matchesBeanName(candidateName, descriptor.getDependencyName())) {
 | 
				
			||||||
				return candidateBeanName;
 | 
									return candidateName;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return null;
 | 
							return null;
 | 
				
			||||||
| 
						 | 
					@ -1294,15 +1322,15 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Determine the primary candidate in the given set of beans.
 | 
						 * Determine the primary candidate in the given set of beans.
 | 
				
			||||||
	 * @param candidateBeans a Map of candidate names and candidate instances
 | 
						 * @param candidates a Map of candidate names and candidate instances
 | 
				
			||||||
	 * that match the required type
 | 
						 * (or candidate classes if not created yet) that match the required type
 | 
				
			||||||
	 * @param requiredType the target dependency type to match against
 | 
						 * @param requiredType the target dependency type to match against
 | 
				
			||||||
	 * @return the name of the primary candidate, or {@code null} if none found
 | 
						 * @return the name of the primary candidate, or {@code null} if none found
 | 
				
			||||||
	 * @see #isPrimary(String, Object)
 | 
						 * @see #isPrimary(String, Object)
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	protected String determinePrimaryCandidate(Map<String, Object> candidateBeans, Class<?> requiredType) {
 | 
						protected String determinePrimaryCandidate(Map<String, Object> candidates, Class<?> requiredType) {
 | 
				
			||||||
		String primaryBeanName = null;
 | 
							String primaryBeanName = null;
 | 
				
			||||||
		for (Map.Entry<String, Object> entry : candidateBeans.entrySet()) {
 | 
							for (Map.Entry<String, Object> entry : candidates.entrySet()) {
 | 
				
			||||||
			String candidateBeanName = entry.getKey();
 | 
								String candidateBeanName = entry.getKey();
 | 
				
			||||||
			Object beanInstance = entry.getValue();
 | 
								Object beanInstance = entry.getValue();
 | 
				
			||||||
			if (isPrimary(candidateBeanName, beanInstance)) {
 | 
								if (isPrimary(candidateBeanName, beanInstance)) {
 | 
				
			||||||
| 
						 | 
					@ -1310,8 +1338,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
 | 
				
			||||||
					boolean candidateLocal = containsBeanDefinition(candidateBeanName);
 | 
										boolean candidateLocal = containsBeanDefinition(candidateBeanName);
 | 
				
			||||||
					boolean primaryLocal = containsBeanDefinition(primaryBeanName);
 | 
										boolean primaryLocal = containsBeanDefinition(primaryBeanName);
 | 
				
			||||||
					if (candidateLocal && primaryLocal) {
 | 
										if (candidateLocal && primaryLocal) {
 | 
				
			||||||
						throw new NoUniqueBeanDefinitionException(requiredType, candidateBeans.size(),
 | 
											throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(),
 | 
				
			||||||
								"more than one 'primary' bean found among candidates: " + candidateBeans.keySet());
 | 
													"more than one 'primary' bean found among candidates: " + candidates.keySet());
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					else if (candidateLocal) {
 | 
										else if (candidateLocal) {
 | 
				
			||||||
						primaryBeanName = candidateBeanName;
 | 
											primaryBeanName = candidateBeanName;
 | 
				
			||||||
| 
						 | 
					@ -1326,29 +1354,30 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Determine the candidate with the highest priority in the given set of beans. As
 | 
						 * Determine the candidate with the highest priority in the given set of beans.
 | 
				
			||||||
	 * defined by the {@link org.springframework.core.Ordered} interface, the lowest
 | 
						 * <p>Based on {@code @javax.annotation.Priority}. As defined by the related
 | 
				
			||||||
	 * value has the highest priority.
 | 
						 * {@link org.springframework.core.Ordered} interface, the lowest value has
 | 
				
			||||||
	 * @param candidateBeans a Map of candidate names and candidate instances
 | 
						 * the highest priority.
 | 
				
			||||||
	 * that match the required type
 | 
						 * @param candidates a Map of candidate names and candidate instances
 | 
				
			||||||
 | 
						 * (or candidate classes if not created yet) that match the required type
 | 
				
			||||||
	 * @param requiredType the target dependency type to match against
 | 
						 * @param requiredType the target dependency type to match against
 | 
				
			||||||
	 * @return the name of the candidate with the highest priority,
 | 
						 * @return the name of the candidate with the highest priority,
 | 
				
			||||||
	 * or {@code null} if none found
 | 
						 * or {@code null} if none found
 | 
				
			||||||
	 * @see #getPriority(Object)
 | 
						 * @see #getPriority(Object)
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	protected String determineHighestPriorityCandidate(Map<String, Object> candidateBeans, Class<?> requiredType) {
 | 
						protected String determineHighestPriorityCandidate(Map<String, Object> candidates, Class<?> requiredType) {
 | 
				
			||||||
		String highestPriorityBeanName = null;
 | 
							String highestPriorityBeanName = null;
 | 
				
			||||||
		Integer highestPriority = null;
 | 
							Integer highestPriority = null;
 | 
				
			||||||
		for (Map.Entry<String, Object> entry : candidateBeans.entrySet()) {
 | 
							for (Map.Entry<String, Object> entry : candidates.entrySet()) {
 | 
				
			||||||
			String candidateBeanName = entry.getKey();
 | 
								String candidateBeanName = entry.getKey();
 | 
				
			||||||
			Object beanInstance = entry.getValue();
 | 
								Object beanInstance = entry.getValue();
 | 
				
			||||||
			Integer candidatePriority = getPriority(beanInstance);
 | 
								Integer candidatePriority = getPriority(beanInstance);
 | 
				
			||||||
			if (candidatePriority != null) {
 | 
								if (candidatePriority != null) {
 | 
				
			||||||
				if (highestPriorityBeanName != null) {
 | 
									if (highestPriorityBeanName != null) {
 | 
				
			||||||
					if (candidatePriority.equals(highestPriority)) {
 | 
										if (candidatePriority.equals(highestPriority)) {
 | 
				
			||||||
						throw new NoUniqueBeanDefinitionException(requiredType, candidateBeans.size(),
 | 
											throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(),
 | 
				
			||||||
								"Multiple beans found with the same priority ('" + highestPriority + "') " +
 | 
													"Multiple beans found with the same priority ('" + highestPriority +
 | 
				
			||||||
										"among candidates: " + candidateBeans.keySet());
 | 
													"') among candidates: " + candidates.keySet());
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					else if (candidatePriority < highestPriority) {
 | 
										else if (candidatePriority < highestPriority) {
 | 
				
			||||||
						highestPriorityBeanName = candidateBeanName;
 | 
											highestPriorityBeanName = candidateBeanName;
 | 
				
			||||||
| 
						 | 
					@ -1529,7 +1558,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
 | 
				
			||||||
	private class OptionalDependencyFactory {
 | 
						private class OptionalDependencyFactory {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public Object createOptionalDependency(DependencyDescriptor descriptor, String beanName, final Object... args) {
 | 
							public Object createOptionalDependency(DependencyDescriptor descriptor, String beanName, final Object... args) {
 | 
				
			||||||
			DependencyDescriptor descriptorToUse = new DependencyDescriptor(descriptor) {
 | 
								DependencyDescriptor descriptorToUse = new NestedDependencyDescriptor(descriptor) {
 | 
				
			||||||
				@Override
 | 
									@Override
 | 
				
			||||||
				public boolean isRequired() {
 | 
									public boolean isRequired() {
 | 
				
			||||||
					return false;
 | 
										return false;
 | 
				
			||||||
| 
						 | 
					@ -1540,7 +1569,6 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
 | 
				
			||||||
							super.resolveCandidate(beanName, requiredType, beanFactory));
 | 
												super.resolveCandidate(beanName, requiredType, beanFactory));
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			};
 | 
								};
 | 
				
			||||||
			descriptorToUse.increaseNestingLevel();
 | 
					 | 
				
			||||||
			return Optional.ofNullable(doResolveDependency(descriptorToUse, beanName, null, null));
 | 
								return Optional.ofNullable(doResolveDependency(descriptorToUse, beanName, null, null));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1558,9 +1586,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
 | 
				
			||||||
		private final String beanName;
 | 
							private final String beanName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public DependencyObjectProvider(DependencyDescriptor descriptor, String beanName) {
 | 
							public DependencyObjectProvider(DependencyDescriptor descriptor, String beanName) {
 | 
				
			||||||
			this.descriptor = new DependencyDescriptor(descriptor);
 | 
								this.descriptor = new NestedDependencyDescriptor(descriptor);
 | 
				
			||||||
			this.descriptor.increaseNestingLevel();
 | 
								this.optional = (this.descriptor.getDependencyType() == javaUtilOptionalClass);
 | 
				
			||||||
			this.optional = this.descriptor.getDependencyType().equals(javaUtilOptionalClass);
 | 
					 | 
				
			||||||
			this.beanName = beanName;
 | 
								this.beanName = beanName;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1676,7 +1703,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
 | 
				
			||||||
			if (beanDefinition == null) {
 | 
								if (beanDefinition == null) {
 | 
				
			||||||
				return null;
 | 
									return null;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			List<Object> sources = new ArrayList<Object>();
 | 
								List<Object> sources = new ArrayList<Object>(2);
 | 
				
			||||||
			Method factoryMethod = beanDefinition.getResolvedFactoryMethod();
 | 
								Method factoryMethod = beanDefinition.getResolvedFactoryMethod();
 | 
				
			||||||
			if (factoryMethod != null) {
 | 
								if (factoryMethod != null) {
 | 
				
			||||||
				sources.add(factoryMethod);
 | 
									sources.add(factoryMethod);
 | 
				
			||||||
| 
						 | 
					@ -1699,4 +1726,21 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static class NestedDependencyDescriptor extends DependencyDescriptor {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public NestedDependencyDescriptor(DependencyDescriptor original) {
 | 
				
			||||||
 | 
								super(original);
 | 
				
			||||||
 | 
								increaseNestingLevel();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static class MultiElementDependencyDescriptor extends NestedDependencyDescriptor {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public MultiElementDependencyDescriptor(DependencyDescriptor original) {
 | 
				
			||||||
 | 
								super(original);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1435,12 +1435,14 @@ public class DefaultListableBeanFactoryTests {
 | 
				
			||||||
	public void testGetBeanByTypeWithPrimary() throws Exception {
 | 
						public void testGetBeanByTypeWithPrimary() throws Exception {
 | 
				
			||||||
		DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
 | 
							DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
 | 
				
			||||||
		RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class);
 | 
							RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class);
 | 
				
			||||||
 | 
							bd1.setLazyInit(true);
 | 
				
			||||||
		RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class);
 | 
							RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class);
 | 
				
			||||||
		bd2.setPrimary(true);
 | 
							bd2.setPrimary(true);
 | 
				
			||||||
		lbf.registerBeanDefinition("bd1", bd1);
 | 
							lbf.registerBeanDefinition("bd1", bd1);
 | 
				
			||||||
		lbf.registerBeanDefinition("bd2", bd2);
 | 
							lbf.registerBeanDefinition("bd2", bd2);
 | 
				
			||||||
		TestBean bean = lbf.getBean(TestBean.class);
 | 
							TestBean bean = lbf.getBean(TestBean.class);
 | 
				
			||||||
		assertThat(bean.getBeanName(), equalTo("bd2"));
 | 
							assertThat(bean.getBeanName(), equalTo("bd2"));
 | 
				
			||||||
 | 
							assertFalse(lbf.containsSingleton("bd1"));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Test
 | 
						@Test
 | 
				
			||||||
| 
						 | 
					@ -1760,24 +1762,6 @@ public class DefaultListableBeanFactoryTests {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Test
 | 
					 | 
				
			||||||
	public void testAutowireBeanByTypeWithTwoMatchesAndParameterNameDiscovery() {
 | 
					 | 
				
			||||||
		DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
 | 
					 | 
				
			||||||
		RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
 | 
					 | 
				
			||||||
		RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class);
 | 
					 | 
				
			||||||
		lbf.registerBeanDefinition("test", bd);
 | 
					 | 
				
			||||||
		lbf.registerBeanDefinition("spouse", bd2);
 | 
					 | 
				
			||||||
		try {
 | 
					 | 
				
			||||||
			lbf.autowire(DependenciesBean.class, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
 | 
					 | 
				
			||||||
			fail("Should have thrown UnsatisfiedDependencyException");
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		catch (UnsatisfiedDependencyException ex) {
 | 
					 | 
				
			||||||
			// expected
 | 
					 | 
				
			||||||
			assertTrue(ex.getMessage().contains("test"));
 | 
					 | 
				
			||||||
			assertTrue(ex.getMessage().contains("spouse"));
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Test
 | 
						@Test
 | 
				
			||||||
	public void testAutowireBeanByTypeWithDependencyCheck() {
 | 
						public void testAutowireBeanByTypeWithDependencyCheck() {
 | 
				
			||||||
		DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
 | 
							DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1146,12 +1146,15 @@ public class AutowiredAnnotationBeanPostProcessorTests {
 | 
				
			||||||
		RootBeanDefinition tb1 = new RootBeanDefinition(TestBean.class);
 | 
							RootBeanDefinition tb1 = new RootBeanDefinition(TestBean.class);
 | 
				
			||||||
		tb1.setPrimary(true);
 | 
							tb1.setPrimary(true);
 | 
				
			||||||
		bf.registerBeanDefinition("testBean1", tb1);
 | 
							bf.registerBeanDefinition("testBean1", tb1);
 | 
				
			||||||
		bf.registerBeanDefinition("testBean2", new RootBeanDefinition(TestBean.class));
 | 
							RootBeanDefinition tb2 = new RootBeanDefinition(TestBean.class);
 | 
				
			||||||
 | 
							tb2.setLazyInit(true);
 | 
				
			||||||
 | 
							bf.registerBeanDefinition("testBean2", tb2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		SmartObjectFactoryInjectionBean bean = (SmartObjectFactoryInjectionBean) bf.getBean("annotatedBean");
 | 
							SmartObjectFactoryInjectionBean bean = (SmartObjectFactoryInjectionBean) bf.getBean("annotatedBean");
 | 
				
			||||||
		assertSame(bf.getBean("testBean1"), bean.getTestBean());
 | 
							assertSame(bf.getBean("testBean1"), bean.getTestBean());
 | 
				
			||||||
		assertSame(bf.getBean("testBean1"), bean.getOptionalTestBean());
 | 
							assertSame(bf.getBean("testBean1"), bean.getOptionalTestBean());
 | 
				
			||||||
		assertSame(bf.getBean("testBean1"), bean.getUniqueTestBean());
 | 
							assertSame(bf.getBean("testBean1"), bean.getUniqueTestBean());
 | 
				
			||||||
 | 
							assertFalse(bf.containsSingleton("testBean2"));
 | 
				
			||||||
		bf.destroySingletons();
 | 
							bf.destroySingletons();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Copyright 2002-2014 the original author or authors.
 | 
					 * Copyright 2002-2016 the original author or authors.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
					 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 * you may not use this file except in compliance with the License.
 | 
					 * you may not use this file except in compliance with the License.
 | 
				
			||||||
| 
						 | 
					@ -48,9 +48,10 @@ public abstract class OrderUtils {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Return the order on the specified {@code type}.
 | 
						 * Return the order on the specified {@code type}.
 | 
				
			||||||
	 * <p>Take care of {@link Order @Order} and {@code @javax.annotation.Priority}.
 | 
						 * <p>Takes care of {@link Order @Order} and {@code @javax.annotation.Priority}.
 | 
				
			||||||
	 * @param type the type to handle
 | 
						 * @param type the type to handle
 | 
				
			||||||
	 * @return the order value, or {@code null} if none can be found
 | 
						 * @return the order value, or {@code null} if none can be found
 | 
				
			||||||
 | 
						 * @see #getPriority(Class)
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public static Integer getOrder(Class<?> type) {
 | 
						public static Integer getOrder(Class<?> type) {
 | 
				
			||||||
		return getOrder(type, null);
 | 
							return getOrder(type, null);
 | 
				
			||||||
| 
						 | 
					@ -59,9 +60,10 @@ public abstract class OrderUtils {
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Return the order on the specified {@code type}, or the specified
 | 
						 * Return the order on the specified {@code type}, or the specified
 | 
				
			||||||
	 * default value if none can be found.
 | 
						 * default value if none can be found.
 | 
				
			||||||
	 * <p>Take care of {@link Order @Order} and {@code @javax.annotation.Priority}.
 | 
						 * <p>Takes care of {@link Order @Order} and {@code @javax.annotation.Priority}.
 | 
				
			||||||
	 * @param type the type to handle
 | 
						 * @param type the type to handle
 | 
				
			||||||
	 * @return the priority value, or the specified default order if none can be found
 | 
						 * @return the priority value, or the specified default order if none can be found
 | 
				
			||||||
 | 
						 * @see #getPriority(Class)
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public static Integer getOrder(Class<?> type, Integer defaultOrder) {
 | 
						public static Integer getOrder(Class<?> type, Integer defaultOrder) {
 | 
				
			||||||
		Order order = AnnotationUtils.findAnnotation(type, Order.class);
 | 
							Order order = AnnotationUtils.findAnnotation(type, Order.class);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue