关于spring:Autowired注解自动装配之bean选择分析

74次阅读

共计 6248 个字符,预计需要花费 16 分钟才能阅读完成。

抛出问题

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);
    }
}
@Bean
public User user(){return new User(1L,"张三");
}

@Bean
public 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 办法里本人去找吧。

正文完
 0