我是靠谱客的博主 醉熏西牛,最近开发中收集的这篇文章主要介绍Spring源码分析:多个bean同时满足注入条件时,spring的选择1、根据bean名称进行属性注入的方式(autowireByName)2、根据bean的类型进行注入(autowireByType)3、注入由注解标注的域4、resolveDependency--寻找符合条件的Bean5、Spring对多个bean符合注入条件时的选择 6、总结,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

今天在翻阅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


对于寻找类型匹配的逻辑是在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,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,即不会抛出异常


当通过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源码深度解析》-- 郝佳
























最后

以上就是醉熏西牛为你收集整理的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、总结所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(56)

评论列表共有 0 条评论

立即
投稿
返回
顶部