概述
今天在翻阅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)) {
//递归初始化相关的bean
Object 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类型来寻找符合依赖条件的bean
value = 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
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,boolean allowEagerInit)方法,如果感兴趣可以自行翻阅源码),
然后将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返回的是Class
candidates.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,返回null
if (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;
}
// Fallback
for (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,即不会抛出异常
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源码深度解析》-- 郝佳
最后
以上就是醉熏西牛为你收集整理的Spring源码分析:多个bean同时满足注入条件时,spring的选择1、根据bean名称进行属性注入的方式(autowireByName)2、根据bean的类型进行注入(autowireByType)3、注入由注解标注的域4、resolveDependency--寻找符合条件的Bean5、Spring对多个bean符合注入条件时的选择 6、总结的全部内容,希望文章能够帮你解决Spring源码分析:多个bean同时满足注入条件时,spring的选择1、根据bean名称进行属性注入的方式(autowireByName)2、根据bean的类型进行注入(autowireByType)3、注入由注解标注的域4、resolveDependency--寻找符合条件的Bean5、Spring对多个bean符合注入条件时的选择 6、总结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复