Spring源码分析:多个bean同时满足注入条件时,spring的选择

来源:互联网 发布:js判断不等于0 编辑:程序博客网 时间:2024/06/07 23:10

今天在翻阅Spring的源码时,看到了spring中对属性注入的处理,突然想到如果需要注入的接口有多个实现类,spring会如何解决的问题(Spring的版本为4.3.7)。

//如果对源码的分析没有兴趣,可以直接跳到最后总结部分

spring中的注入方式有两种:通过bean的名字进行注入或者根据类型进行注入。

Spring在创建Bean实例后,进行依赖注入的代码是:

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {PropertyValues pvs = mbd.getPropertyValues();//省略:如果bw为null则不用注入,直接返回// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the// state of the bean before properties are set. This can be used, for example,// to support styles of field injection.boolean continueWithPropertyPopulation = true;if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {//完成注解标注的属性注入InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {continueWithPropertyPopulation = false;break;}}}}if (!continueWithPropertyPopulation) {return;}//在<bean></bean>标签中可以指定default-autowire来进行注入// 在不设置<beans default-autowire="byName/byType"/>的情况下是不会调用方法的if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {MutablePropertyValues newPvs = new MutablePropertyValues(pvs);// Add property values based on autowire by name if applicable.if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {autowireByName(beanName, mbd, bw, newPvs);}// Add property values based on autowire by type if applicable.if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {autowireByType(beanName, mbd, bw, newPvs);}pvs = newPvs;}boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);if (hasInstAwareBpps || needsDepCheck) {PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);if (hasInstAwareBpps) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {//通过注解进行标注的域在此处通过AutowiredAnnotationBeanPostProcessor完成注入InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);if (pvs == null) {return;}}}}if (needsDepCheck) {checkDependencies(beanName, mbd, filteredPds, pvs);}}//将属性注入到实例中applyPropertyValues(beanName, mbd, bw, pvs);}


1、根据bean名称进行属性注入的方式(autowireByName)

例如:

@Resource(name = "userService")    private UserService userService;
@Autowired    @Qualifier(value = "articleService")    private ArticleService articleService;

这两种方式都是指定bean的名称完成注入,Spring的实现也更简单,也就是递归创建bean并且完成注入就行了:

protected void autowireByName(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {//寻找BeanWrapper(对beanInstance的包装类)中需要依赖注入的属性String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);for (String propertyName : propertyNames) {if (containsBean(propertyName)) {//递归初始化相关的beanObject bean = getBean(propertyName);pvs.add(propertyName, bean);//注册依赖registerDependentBean(propertyName, beanName);if (logger.isDebugEnabled()) {logger.debug("Added autowiring by name from bean name '" + beanName +"' via property '" + propertyName + "' to bean named '" + propertyName + "'");}}else {if (logger.isTraceEnabled()) {logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +"' by name: no matching bean found");}}}}

因为bean的name在IOC容器中是独一无二的,所以不会存在多个bean满足注入条件的情况。

2、根据bean的类型进行注入(autowireByType)

由于是根据bean的类型进行选择相应bean进行注入,所以就存在一个接口有多个实现类同时存在的情况。

//下面是跟踪Spring通过autowireByType()方法,搜索匹配类型的bean列表的源码,如果只关注如何选择bean的话可以直接掠过到最后的第5部分

下面是根据属性注入的总体源码:

protected void autowireByType(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {TypeConverter converter = getCustomTypeConverter();if (converter == null) {converter = bw;}Set<String> autowiredBeanNames = new LinkedHashSet<String>(4);//寻找BeanWrapper中需要依赖注入的属性String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);for (String propertyName : propertyNames) {try {PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);// Don't try autowiring by type for type Object: never makes sense,// even if it technically is a unsatisfied, non-simple property.if (Object.class != pd.getPropertyType()) {//寻找属性的set方法MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);// Do not allow eager init for type matching in case of a prioritized post-processor.boolean eager = !PriorityOrdered.class.isAssignableFrom(bw.getWrappedClass());DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);//在这一步完成对指定beanName的属性进行解析,并将解析到的属性名称存放在autowiredBeanNames中Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);if (autowiredArgument != null) {pvs.add(propertyName, autowiredArgument);}for (String autowiredBeanName : autowiredBeanNames) {//注册依赖registerDependentBean(autowiredBeanName, beanName);if (logger.isDebugEnabled()) {logger.debug("Autowiring by type from bean name '" + beanName + "' via property '" +propertyName + "' to bean named '" + autowiredBeanName + "'");}}autowiredBeanNames.clear();}}catch (BeansException ex) {throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);}}}

可以看到通过Bean类型完成依赖注入是在resolveDependency函数中实现的,在探究这部分源码前,我们先看一下另一个被@Autowired标注注入的域完成注入的方法:

3、注入由注解标注的域

Spring中通过一系列的BeanPostProcessor使得其有很强的扩展性,比如通过AutowiredAnnotationBeanPostProcessor这个类为注解标注的属性进行注入。

AutowiredAnnotationBeanPostProcessor继承了InstantiationAwareBeanPostProcessor,在前面的populateBean方法中有这么一段代码:

for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {continueWithPropertyPopulation = false;break;}}}
所以会调用AutowiredAnnotationBeanPostProcessor的postProcessPropertyValues方法完成注入:

public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {//获取类中所有标注了@Autowired和@Value注解以及@Inject注解的字段(包括Field和Method两种类型),也就是探测有哪些属性需要被自动装配InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);try {//完成注入的地方metadata.inject(bean, beanName, pvs);}catch (BeanCreationException ex) {throw ex;}catch (Throwable ex) {throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);}return pvs;}

public void inject(Object target, String beanName, PropertyValues pvs) throws Throwable {Collection<InjectedElement> elementsToIterate =(this.checkedElements != null ? this.checkedElements : this.injectedElements);if (!elementsToIterate.isEmpty()) {boolean debug = logger.isDebugEnabled();//遍历其中的所有InjectionElement对象,调用其中的inject方法。//InjectionElement有两个实现类:AutowiredFieldElement和AutowiredMethodElement(对应注解标注在Field字段上和set方法上)for (InjectedElement element : elementsToIterate) {if (debug) {logger.debug("Processing injected element of bean '" + beanName + "': " + element);}element.inject(target, beanName, pvs);//在这里完成自动注入}}}
有两种注入方式:通过Filed注入和setMethod注入,以为大致原理相同,这里我们只看Field注入的方式:

protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {Field field = (Field) this.member;Object value;if (this.cached) {value = resolvedCachedArgument(beanName, this.cachedFieldValue);}else {DependencyDescriptor desc = new DependencyDescriptor(field, this.required);desc.setContainingClass(bean.getClass());Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);TypeConverter typeConverter = beanFactory.getTypeConverter();try {//重点的地方,和前面的AutowireByType相同,都是通过bean类型来寻找符合依赖条件的beanvalue = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);}catch (BeansException ex) {throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);}//省略将结果加入缓存的部分}if (value != null) {//最终在这里通过反射完成了依赖的注入ReflectionUtils.makeAccessible(field);field.set(bean, value);}}}

4、resolveDependency--寻找符合条件的Bean


对于寻找类型匹配的逻辑是在resolveDependency(desc, beanName, autowiredBeanNames, converter);中实现的:

public Object resolveDependency(DependencyDescriptor descriptor, String requestingBeanName,Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());if (javaUtilOptionalClass == descriptor.getDependencyType()) {return new OptionalDependencyFactory().createOptionalDependency(descriptor, requestingBeanName);}else if (ObjectFactory.class == descriptor.getDependencyType() ||ObjectProvider.class == descriptor.getDependencyType()) {return new DependencyObjectProvider(descriptor, requestingBeanName);}else if (javaxInjectProviderClass == descriptor.getDependencyType()) {return new Jsr330ProviderFactory().createDependencyProvider(descriptor, requestingBeanName);}else {Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(descriptor, requestingBeanName);if (result == null) {//通用处理逻辑result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);}return result;}}

我们进入到通用的处理逻辑中:

public Object doResolveDependency(DependencyDescriptor descriptor, String beanName,Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);try {Object shortcut = descriptor.resolveShortcut(this);if (shortcut != null) {return shortcut;}//获取需要注入的属性的类型(需要注入的属性的相关信息是封装在了DependencyDescriptor中)Class<?> type = descriptor.getDependencyType();//获取@Value注解中的值Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);if (value != null) {//如果value值不为空,则TypeConverter将value转换成相应类型后,直接返回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()));}//如果需要注入的属性是数组或者List等类型的处理Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);if (multipleBeans != null) {return multipleBeans;}//如果不是数组等类型,就找出所有满足要求的bean,再进行进一步的处理Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);if (matchingBeans.isEmpty()) {if (descriptor.isRequired()) {raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);}return null;}String autowiredBeanName;Object instanceCandidate;//当有多个bean匹配类型的情况if (matchingBeans.size() > 1) {autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);if (autowiredBeanName == null) {if (descriptor.isRequired() || !indicatesMultipleBeans(type)) {return descriptor.resolveNotUnique(type, matchingBeans);}else {// In case of an optional Collection/Map, silently ignore a non-unique case:// possibly it was meant to be an empty collection of multiple regular beans// (before 4.3 in particular when we didn't even look for collection beans).return null;}}instanceCandidate = matchingBeans.get(autowiredBeanName);}else {//只有唯一的bean类型匹配,就返回这个bean// We have exactly one match.Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();autowiredBeanName = entry.getKey();instanceCandidate = entry.getValue();}if (autowiredBeanNames != null) {autowiredBeanNames.add(autowiredBeanName);}return (instanceCandidate instanceof Class ?descriptor.resolveCandidate(autowiredBeanName, type, this) : instanceCandidate);}finally {ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);}}

从上面的代码可以看出,spring对注入情况分为3类:

1、如果存在@Value注解,就直接解析注解的value值,然后通过类型转换器进行类型转换后就得到了想要的值;

2、如果需要注入的数组、List等类型,就找出类型匹配的beans返回;

3、如果是一个非数组类型,找到所有匹配的beans后还需要进行一些判断,下文会详细说明;


我们先看数组类型的处理的源码:

//数组类型的处理private Object resolveMultipleBeans(DependencyDescriptor descriptor, String beanName,Set<String> autowiredBeanNames, TypeConverter typeConverter) {Class<?> type = descriptor.getDependencyType();//对于数组、Collection、Map,spring是分开处理的,但是大致逻辑都十分详细//可以看到不管是那种类型,对bean的搜寻都是放在了findAutowireCandidates函数中if (type.isArray()) {Class<?> componentType = type.getComponentType();ResolvableType resolvableType = descriptor.getResolvableType();Class<?> resolvedArrayType = resolvableType.resolve();if (resolvedArrayType != null && resolvedArrayType != type) {type = resolvedArrayType;componentType = resolvableType.getComponentType().resolve();}if (componentType == null) {return null;}Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType,new MultiElementDescriptor(descriptor));if (matchingBeans.isEmpty()) {return null;}if (autowiredBeanNames != null) {autowiredBeanNames.addAll(matchingBeans.keySet());}TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());Object result = converter.convertIfNecessary(matchingBeans.values(), type);if (getDependencyComparator() != null && result instanceof Object[]) {Arrays.sort((Object[]) result, adaptDependencyComparator(matchingBeans));}return result;}else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();if (elementType == null) {return null;}Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,new MultiElementDescriptor(descriptor));if (matchingBeans.isEmpty()) {return null;}if (autowiredBeanNames != null) {autowiredBeanNames.addAll(matchingBeans.keySet());}TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());Object result = converter.convertIfNecessary(matchingBeans.values(), type);if (getDependencyComparator() != null && result instanceof List) {Collections.sort((List<?>) result, adaptDependencyComparator(matchingBeans));}return result;}else if (Map.class == type) {ResolvableType mapType = descriptor.getResolvableType().asMap();Class<?> keyType = mapType.resolveGeneric(0);if (String.class != keyType) {return null;}Class<?> valueType = mapType.resolveGeneric(1);if (valueType == null) {return null;}Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType,new MultiElementDescriptor(descriptor));if (matchingBeans.isEmpty()) {return null;}if (autowiredBeanNames != null) {autowiredBeanNames.addAll(matchingBeans.keySet());}return matchingBeans;}else {return null;}}

由于是分类进行处理的,所以上面的代码比较长,但是对bean的搜寻都是放在了findAutowireCandidates函数中。并且如果仔细看的话,其实对非数组类型而言,对bean的搜寻也是在该函数中,只是入参稍有不同:

//数组类型Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType,new MultiElementDescriptor(descriptor));//非数组类型Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);

findAutowireCandidates实现如下:

protected Map<String, Object> findAutowireCandidates(String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {//获取候选bean的beanName列表String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this, requiredType, true, descriptor.isEager());Map<String, Object> result = new LinkedHashMap<String, Object>(candidateNames.length);for (Class<?> autowiringType : this.resolvableDependencies.keySet()) {if (autowiringType.isAssignableFrom(requiredType)) {Object autowiringValue = this.resolvableDependencies.get(autowiringType);autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);if (requiredType.isInstance(autowiringValue)) {result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);break;}}}//将匹配的beanName(保证beanName锁对应bean不是自身)和bean实例加入到result中for (String candidate : candidateNames) {if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {addCandidateEntry(result, candidate, descriptor, requiredType);}}//...return result;}

首先是通过BeanFactory获取其记录的bean中匹配类型的beanName列表(最终是通过调用BeanFactory的getBeanNamesForType(Class<?> type,booleanincludeNonSingletons,booleanallowEagerInit)方法,如果感兴趣可以自行翻阅源码),

然后将beanName和实例存到result的map中:


private void addCandidateEntry(Map<String, Object> candidates, String candidateName,DependencyDescriptor descriptor, Class<?> requiredType) {//MultiElementDescriptor对应上文中对数组类型处理是传入的DependencyDescriptor//如果descriptor属于MultiElementDescriptor类型,即对数组类型的处理//或者该beanName对应的bean是单例模式if (descriptor instanceof MultiElementDescriptor || containsSingleton(candidateName)) {candidates.put(candidateName, descriptor.resolveCandidate(candidateName, requiredType, this));}else {//getType返回的是Classcandidates.put(candidateName, getType(candidateName));}}//进入resolveCandidate方法:public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)throws BeansException {return beanFactory.getBean(beanName, requiredType);}

从这里可以看到:Spring是转了很大一个弯,通过待注入的field类型,来获取满足匹配的bean的name列表,最终是getBean(beanName,requiredType)获取bean的实例,然后加入到bean列表中.

如果需要注入的属性是数组类型,那么就直接返回,下面分析的就是开头提到的如果需要注入的接口有多个实现类,spring会如何解决的问题。

//BeanFactory.getBean(beanName,requiredType)较为复杂,如果对该部分有兴趣,可自行阅读源码,具体实现是在AbstractBeanFactory.doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)方法中

5、Spring对多个bean符合注入条件时的选择

直到这里,spring终于完成了对bean列表的寻找,然后回到前面的doResolveDependency方法,下面只贴出剩下未分析的代码:

                        //在前面代码中获取的bean列表Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);//如果列表为空,而且required属性为true,会转入raiseNoMatchingBeanFound方法,该方法抛出NoSuchBeanDefinitionException异常//如果required属性为false,表示可以注入null值if (matchingBeans.isEmpty()) {if (descriptor.isRequired()) {raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);}return null;}String autowiredBeanName;Object instanceCandidate;//有多个bean匹配的情况if (matchingBeans.size() > 1) {//选择到底是哪一个bean进行注入autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);//如果没有选择到bean,而且required属性为true,会进入resolveNotUnique方法,该方法会抛出NoUniqueBeanDefinitionException异常//如果required属性为false,返回nullif (autowiredBeanName == null) {//如果注解中没有表明required=false,则会抛出异常if (descriptor.isRequired() || !indicatesMultipleBeans(type)) {return descriptor.resolveNotUnique(type, matchingBeans);}else {// In case of an optional Collection/Map, silently ignore a non-unique case:// possibly it was meant to be an empty collection of multiple regular beans// (before 4.3 in particular when we didn't even look for collection beans).return null;}}//如果选择到了具体是哪一个bean,返回该bean实例instanceCandidate = matchingBeans.get(autowiredBeanName);}else {//只有一个bean匹配,则返回该bean实例// We have exactly one match.Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();autowiredBeanName = entry.getKey();instanceCandidate = entry.getValue();}if (autowiredBeanNames != null) {autowiredBeanNames.add(autowiredBeanName);}return (instanceCandidate instanceof Class ?descriptor.resolveCandidate(autowiredBeanName, type, this) : instanceCandidate);

从上面代码可以看出,如果只有一个bean符合要求,Spring直接返回这个bean的name,然后在属性注入环节注入就行了;如果有多个bean匹配的情况下,Spring会选择出一个最佳匹配项,选择方式有下文列举的三种:是否带有Primary注解,是否优先级最高,是否beanName向对应;如果没有找到最佳项则抛出异常

下面进入到从多个bean中选择最为匹配项的函数determineAutowireCandidate():

protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {Class<?> requiredType = descriptor.getDependencyType();//存在Primary注解的情况String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);if (primaryCandidate != null) {return primaryCandidate;}//存在javax.annotation.Priority注解的情况String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);if (priorityCandidate != null) {return priorityCandidate;}// Fallbackfor (Map.Entry<String, Object> entry : candidates.entrySet()) {String candidateName = entry.getKey();Object beanInstance = entry.getValue();//如果需要的注入的属性的名称与多个bean中的某个bean的name相同(即名字相同)的情况if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||matchesBeanName(candidateName, descriptor.getDependencyName())) {return candidateName;}}return null;}

这里先说明一下isRequired()方法表示的意思,在我们使用spring的Autowired注解时,我们可以选择让Spring即使找不到匹配的bean完成注入也不要抛出异常,那么就可以使用如下的声明方式:

public class UserServiceTest {    @Autowired(required = false)    private UserService userService;//...}

采用这种方式后,descriptor.isRequired()返回的就是false,即不会抛出异常


当通过autowiredByType进行注入时,会存在已下几种情况:
1、如果满足的bean列表中存在bean有@Primary注解,将注入该bean,例如:
   
    //@primary注解的使用示例    @Primary    @Component    public class OperaSinger implements Singer{        @Override        public String sing(String lyrics) {            return "I am singing in Bocelli voice: "+lyrics;        }    }        //spring源码:    protected String determinePrimaryCandidate(Map<String, Object> candidates, Class<?> requiredType) {        String primaryBeanName = null;        for (Map.Entry<String, Object> entry : candidates.entrySet()) {            //获取beanName和实例            String candidateBeanName = entry.getKey();            Object beanInstance = entry.getValue();            //判断是否有Primary注解            if (isPrimary(candidateBeanName, beanInstance)) {                if (primaryBeanName != null) {                //当存在多个bean都有Primary注解时,抛出NoUniqueBeanDefinitionException异常                    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;                }            }        }        //返回带有Primary注解的bean的beanName        return primaryBeanName;    }        protected boolean isPrimary(String beanName, Object beanInstance) {        if (containsBeanDefinition(beanName)) {            //通过对应的beanDefinition判断是否有Primary注解            return getMergedLocalBeanDefinition(beanName).isPrimary();        }        //如果该BeanFactory存在ParentBeanFactory则递归调用        BeanFactory parent = getParentBeanFactory();        return (parent instanceof DefaultListableBeanFactory &&                ((DefaultListableBeanFactory) parent).isPrimary(beanName, beanInstance));    }



    
2、如果bean上声明有javax.annotation.Priority注解,将以注解中value值中最小(优先级最高)的bean注入

    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();            //根据bean实例获取Priority注解的value值            Integer candidatePriority = getPriority(beanInstance);            if (candidatePriority != null) {                if (highestPriorityBeanName != null) {                    //如果存在两个最高优先级,抛出NoUniqueBeanDefinitionException异常                    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) {//选取的是Priority值最小的bean                        highestPriorityBeanName = candidateBeanName;                        highestPriority = candidatePriority;                    }                }                else {                    highestPriorityBeanName = candidateBeanName;                    highestPriority = candidatePriority;                }            }        }        return highestPriorityBeanName;    }


    
3、如果需要的注入的field的名称与多个bean中的某个bean的name值相同,则返回该bean:
       
for (Map.Entry<String, Object> entry : candidates.entrySet()) {            String candidateName = entry.getKey();            Object beanInstance = entry.getValue();            if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||                    //如果名称相同就返回该bean的name                    matchesBeanName(candidateName, descriptor.getDependencyName())) {                return candidateName;            }        }




//TODO   三种情况的结果演示


6、总结

总的来说,Spring对多个bean符合注入条件时的处理有以下几种:

1、如果满足的bean列表中存在bean有@Primary注解,将注入该bean。但是如果同时有两个及以上的bean有@Primary注解,则会抛出NoUniqueBeanDefinitionException异常

2、如果存在bean带有javax.annotation.Priority注解,将以注解中value值中最小(优先级最高)的bean注入。但是如果有两个bean的优先级相同且都是最高,则会抛出NoUniqueBeanDefinitionException异常

3、如果需要的注入的属性的名称与多个bean中的某个bean的name相同,则注入该bean

4、上面条件都不满足,但是如果需要的注入的field上的注解为@Autowired(required=false)则返回null,不会抛出异常

5、抛出NoUniqueBeanDefinitionException异常











//如果错误,欢迎指正



--参考:

《Spring源码深度解析》-- 郝佳