抛出问题

spring启动中NoUniqueBeanDefinitionException异样是开发人员常常碰到的异样之一。呈现NoUniqueBeanDefinitionException 个别的做法有:1、应用Qualifier 注解明确bean 2、指定一个bean为primary bean来解决。

然而在理论中碰到了一个意外,如下代码:
public class User {    Long id;    String name;    public User(Long id, String name) {        this.id = id;        this.name = name;    }}public class VipUser  extends  User{    public VipUser(Long id, String name) {        super(id, name);    }}
@Beanpublic User user(){    return new User(1L,"张三");}@Beanpublic VipUser vipUser(){    return new VipUser(2L, "李四");}
public class DependecyDescribleTest {    @Autowired    User user;    public static void main(String[] args) {       ........    }}

启动后,User类型的bean 注册了两个,一个是name为user的User对象,一个是name为vipUser的VipUser对象。 在启动类中主动拆卸 User user。我的项目中没有@Primary进行注解,也没有应用@Qualifier ,依照刻板印象,那么应该会抛出NoUniqueBeanDefinitionException,理论状况是
,理论状况是运行失常。 同理将User user 改为User vipUser也运行失常, 而改为User user1 则抛出异样NoUniqueBeanDefinitionException。这阐明在 @Autowired进行拆卸时,能依据字段名称就行拆卸。

spring源码解读(版本5.3.15)

咱们先不思考@Autowired 拆卸的具体细节。Autowired的最终拆卸会调用到DefaultListableBeanFactory的resolveDependency 办法。resolveDependency 会依据依赖形容返回适合的bean对象,这是spring factory中十分重要的一个办法。

/** * 通过此工厂中定义的 bean 解决指定的依赖关系。 */Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,            @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException{    descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());        if (Optional.class == descriptor.getDependencyType()) {            return 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 Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);        }        else {            Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(                    descriptor, requestingBeanName);            if (result == null) {                result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);            }            return result;        }}

拿下面的例子看,咱们申请的对象不是Optional类型、不是ObjectFactory对象也不是javax.inject.Provider对象,最终会调用doResolveDependency 办法。

public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,            @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {        InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);        try {            //shortcut翻译为捷径,这里我认为是缓存。 解析过的DependencyDescriptor 通过一些缓存的形式,防止下一次的解析。            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());                try {                    return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());                }                catch (UnsupportedOperationException ex) {                    // A custom TypeConverter which does not support TypeDescriptor resolution...                    return (descriptor.getField() != null ?                            converter.convertIfNecessary(value, type, descriptor.getField()) :                            converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));                }            }    // 解析的descriptor是一个数组、容器的形容,调用            Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);            if (multipleBeans != null) {                return multipleBeans;            }        // 查找合乎依赖描述符的候选者,返回matchingBeans 的key 是候选者beanName,value 可能是bean对象也可能是class。            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) {            //决定有没有适合的候选者。                autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);//如果上边的办法决定不了一个后抉择,那么抛出异样                if (autowiredBeanName == null) {                    if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {                        return descriptor.resolveNotUnique(descriptor.getResolvableType(), 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 {                // 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);            }            if (instanceCandidate instanceof Class) {                instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);            }            Object result = instanceCandidate;            if (result instanceof NullBean) {                if (isRequired(descriptor)) {                    raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);                }                result = null;            }            if (!ClassUtils.isAssignableValue(type, result)) {                throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());            }            return result;        }        finally {            ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);        }    }

doResolveDependency办法的代码比拟多,做了一些简略正文。真正决定依赖描述符的返回值的是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;        }        // 最初的兜底(应为: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;            }        }        return null;    }

从下面的代码剖析,大略了解了autowire抉择候选者的过程 1、primary 2、是否存在javax.annotation.Priority 注解的候选者 3、名字雷同。
读到这里可能还有个疑难,那么文章结尾里说过能够应用Qualifier,Qualifier是如何工作的呢? findAutowireCandidates 办法里本人去找吧。