spring版本5.0.4
spring的自动装配 我们一般通过加注解的方式来实现,@Resource 或者@Autowired。处理自动装配的类为DefaultListableBeanFactory,部分源码如下:
@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
Class<?> type = descriptor.getDependencyType();
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
if (value instanceof String) {
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
value = evaluateBeanDefinitionString(strVal, bd);
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
if (matchingBeans.size() > 1) {
//有多个bean匹配执行determinaAutowireCandidate方法获取最终匹配的bean
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(type, matchingBeans);
}
如果存在实现相同接口的多个类实例化在spring容器中的时候,这种情况本人在项目中有遇到,不同实现在不同的maven模块,根据打包不同的maven模块注入不同的实现,对于类似情况的处理,我们需要用到装配的优先级处理,spring在自动装配时是支持装配优先级的处理的,下面贴一下spirng自动装配的源码和个人的分析,忘能帮助遇到类型情况的小伙伴。spring自动装配的规则如下:
/** * Determine the autowire candidate in the given set of beans. * <p>Looks for {@code @Primary} and {@code @Priority} (in that order). * @param candidates a Map of candidate names and candidate instances * that match the required type, as returned by {@link #findAutowireCandidates} * @param descriptor the target dependency to match against * @return the name of the autowire candidate, or {@code null} if none found */ @Nullable protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) { Class<?> requiredType = descriptor.getDependencyType(); //根据@Primary注解进行确定 String primaryCandidate = determinePrimaryCandidate(candidates, requiredType); if (primaryCandidate != null) { return primaryCandidate; } //根据@Priority注解进行确定 String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType); if (priorityCandidate != null) { return priorityCandidate; } // Fallback for (Map.Entry<String, Object> entry : candidates.entrySet()) { String candidateName = entry.getKey(); Object beanInstance = entry.getValue(); if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) || //根据beanName和fieldName是否匹配确定 matchesBeanName(candidateName, descriptor.getDependencyName())) { return candidateName; } } return null;
1.按照bean加了@Primary注解进行匹配,如果存在多个bean有@Primary,会报错,源码截图如下
/** * Determine the primary candidate in the given set of beans. * @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 * @return the name of the primary candidate, or {@code null} if none found * @see #isPrimary(String, Object) */ @Nullable protected String determinePrimaryCandidate(Map<String, Object> candidates, Class<?> requiredType) { String primaryBeanName = null; for (Map.Entry<String, Object> entry : candidates.entrySet()) { String candidateBeanName = entry.getKey(); Object beanInstance = entry.getValue(); if (isPrimary(candidateBeanName, beanInstance)) { if (primaryBeanName != null) { boolean candidateLocal = containsBeanDefinition(candidateBeanName); boolean primaryLocal = containsBeanDefinition(primaryBeanName); if (candidateLocal && primaryLocal) { throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(), "more than one 'primary' bean found among candidates: " + candidates.keySet()); } else if (candidateLocal) { primaryBeanName = candidateBeanName; } } else { primaryBeanName = candidateBeanName; } } } return primaryBeanName; }
2.按照bean加了@Priority进行匹配,@Priority的值越小,优先级越高,如果存在两个相同最高的优先级,会报错
/** * Determine the candidate with the highest priority in the given set of beans. * <p>Based on {@code @javax.annotation.Priority}. As defined by the related * {@link org.springframework.core.Ordered} interface, the lowest value has * the highest priority. * @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 * @return the name of the candidate with the highest priority, * or {@code null} if none found * @see #getPriority(Object) */ @Nullable protected String determineHighestPriorityCandidate(Map<String, Object> candidates, Class<?> requiredType) { String highestPriorityBeanName = null; Integer highestPriority = null; for (Map.Entry<String, Object> entry : candidates.entrySet()) { String candidateBeanName = entry.getKey(); Object beanInstance = entry.getValue(); if (beanInstance != null) { Integer candidatePriority = getPriority(beanInstance); if (candidatePriority != null) { if (highestPriorityBeanName != null) { if (candidatePriority.equals(highestPriority)) { throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(), "Multiple beans found with the same priority ('" + highestPriority + "') among candidates: " + candidates.keySet()); } else if (candidatePriority < highestPriority) { highestPriorityBeanName = candidateBeanName; highestPriority = candidatePriority; } } else { highestPriorityBeanName = candidateBeanName; highestPriority = candidatePriority; } } } } return highestPriorityBeanName; }
3.按照名称进行匹配(beanName和fieldName)
// Fallback for (Map.Entry<String, Object> entry : candidates.entrySet()) { String candidateName = entry.getKey(); Object beanInstance = entry.getValue(); if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) || matchesBeanName(candidateName, descriptor.getDependencyName())) { return candidateName; } }
如果无法确定自动装配的bean,报错: No qualifying bean of type '类型' available: expected single matching bean but found 多个bean匹配
可以根据实际需要,配置优先级