浅析 Spring 依赖解析实现

背景

接上篇《Spring 依赖注入的方式,你了解哪些?》,上篇介绍了 Spring 包括 setter、字段、构造器、方法、接口回调等依赖注入的几种方式以及依赖注入的来源,更多的是停留在认识或者使用层面。这篇从源码的角度进行分析,Spring 在依赖注入的过程中如何解析依赖。

《Spring 中 @Autowired 和 @Resource 有什么区别?》 一文中,我们有提到,Spring 在依赖注入时会先将 @Autowired 注解以及 @Resource 注解标注的对象解析为依赖描述符 DependencyDescriptor,然后调用AutowireCapableBeanFactory#resolveDependency(DependencyDescriptor,String,Set<String>, TypeConverter)解析依赖,最后通过反射设置字段或调用方法达到依赖注入的目的。我们下面就从 resolveDependency 方法进行分析 Spring 如何实现依赖解析。

依赖解析实现分析

Spring 对 BeanFactory 底层的最终实现是 DefaultListableBeanFactory,DefaultListableBeanFactory 对 resolveDependency 方法实现的源码如下。

	/**
	 * @param descriptor         字段或方法的依赖描述信息
	 * @param requestingBeanName 需要注入依赖的 bean 的名称
	 * @param autowiredBeanNames 需要注入的依赖的 bean 名称的集合,解析的结果会存放该集合中
	 * @param typeConverter      类型转换
	 * @return
	 * @throws BeansException
	 */
	@Override
	@Nullable
	public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

		descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
		if (Optional.class == descriptor.getDependencyType()) {
			// 解析 Optional 依赖
			return createOptionalDependency(descriptor, requestingBeanName);
		} else if (ObjectFactory.class == descriptor.getDependencyType() ||
				ObjectProvider.class == descriptor.getDependencyType()) {
			// 解析 ObjectFactory 或 ObjectProvider 依赖
			return new DependencyObjectProvider(descriptor, requestingBeanName);
		} else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
			// 解析 javax.inject.Provider 注解标注的依赖
			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、ObjectProvider 依赖类型,由于需要解析的是其泛型的实际类型,因此 Spring 会将依赖描述信息重新包装为另一个 DependencyDescriptor ,然后再解析。而 Java 规范 JSR-330 中注解 javax.inject.Provider 的处理则只是将实现委托给另一个类处理。对于不同类型的依赖解析,最终都会调用 doResolveDependency 方法。以 Optional 类型的解析方法 createOptionalDependency 为例,源码如下。

	private Optional<?> createOptionalDependency(
			DependencyDescriptor descriptor, @Nullable String beanName, final Object... args) {

		// 包装依赖描述信息,解析依赖的类型时会将嵌套层次加1
		// 例如原来要解析的类型是 Optional<T> 的原始类型,嵌套层次加1后会解析泛型类型的实际类型 T
		DependencyDescriptor descriptorToUse = new NestedDependencyDescriptor(descriptor) {
			@Override
			public boolean isRequired() {
				return false;
			}

			@Override
			public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory) {
				return (!ObjectUtils.isEmpty(args) ? beanFactory.getBean(beanName, args) :
						super.resolveCandidate(beanName, requiredType, beanFactory));
			}
		};
		// 然后真正解析依赖
		Object result = doResolveDependency(descriptorToUse, beanName, null, null);
		// 再将解析出的依赖包装到 Optional 中
		return (result instanceof Optional ? (Optional<?>) result : Optional.ofNullable(result));
	}

跟踪真正解析依赖的方法 doResolveDependency,源码如下。

	public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
		... 省略部分代码
			// 快捷解析依赖
			Object shortcut = descriptor.resolveShortcut(this);
			if (shortcut != null) {
				return shortcut;
			}

			Class<?> type = descriptor.getDependencyType();
			// 先根据 @Value 注解解析依赖对象
			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) {
					... 省略部分代码
				}
			}

			// 尝试解析包含多个 bean 的依赖对象
			Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
			if (multipleBeans != null) {
				return multipleBeans;
			}

			// 查找所需类型的依赖
			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;
	}

真正解析依赖的方法 doResolveDependency 代码稍长,上面省略了部分代码。我们可以看出解析流程如下。

  1. 优先尝试根据依赖描述符快捷进行解析,默认返回 null,实现类 ShortcutDependencyDescriptor 会根据依赖的名称和类型从 BeanFactory 中获取 bean。
  2. 如果快捷解析失败,则尝试解析 @Value 标注的字段,会对 @Value 注解的 value 值中的占位符进行解析,以及解析表达式,最后还会把解析出的对象进行类型转换。
  3. 如果 @Value 注解也解析失败,则会尝试解析包含多个 bean 对象的依赖类型,如集合、数组、Map 等。
  4. 如果依赖的是单一类型,会先根据类型查找除所有的依赖,如果依赖不存在并且依赖是必须的则会抛出异常。
  5. 对于单一类型,如果只查找到一个依赖,那么直接返回即可,否则需要根据 Primary、优先级等选择一个最佳的依赖。

对于集合类型以及单一类型,最终都会调用 findAutowireCandidates 方法查找自动装配的候选对象,对于集合类型会把查找到的候选对象包装为对应所需的类型,对于单一类型则需要确认最终使用哪个依赖。跟踪查找依赖候选对象的方法 findAutowireCandidates ,源码如下。

	protected Map<String, Object> findAutowireCandidates(
			@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
		// 查找 Spring 中给定类型的 bean 名称
		String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
				this, requiredType, true, descriptor.isEager());
		Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
		// 先解析 Spring 中游离的对象,如果类型和所需类型匹配则加入到结果中
		for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
			Class<?> autowiringType = classObjectEntry.getKey();
			if (autowiringType.isAssignableFrom(requiredType)) {
				Object autowiringValue = classObjectEntry.getValue();
				autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
				if (requiredType.isInstance(autowiringValue)) {
					result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
					break;
				}
			}
		}
		// 然后解析 Spring 中注册 BeanDefinition 中的名称
		for (String candidate : candidateNames) {
			if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
				// 依赖非 bean 自身,并且 bean 可以作为候选项,加入到结果中
				addCandidateEntry(result, candidate, descriptor, requiredType);
			}
		}
		... 省略回退处理代码,和上述候选名称循环类似
		return result;
	}

候选对象的获取主要有两个来源,一个是游离对象,一个是 Spring 中的 bean,Spring 根据类型获取到对应的实例后添加到返回结果。这也印证了前面文章所说的依赖注入的依赖来源。需要留意的是对 isAutowireCandidate 方法的调用,isAutowireCandidate 方法用于判断一个一个对象是否可以作为候选项,其内部出了判断 bean 定义中是否可以作为候选项的标识,还会判断泛型、@Qualifier 等。关于 @Qualifier 的处理,我们后面再开一篇进行分析。

对于单一类型的依赖解析,如果查找到了多个 bean,则需要判断到底使用哪一个 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;
		}
		// primary 不存在,则根据优先级判断
		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 名称匹配,直接返回
			if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||
					matchesBeanName(candidateName, descriptor.getDependencyName())) {
				return candidateName;
			}
		}
		return null;
	}

这里优先选择标记 primary 为 true 的 bean,如果都没有标注则会选择一个优先级最高的 bean,如果存在多个优先级相同的 bean 会抛出异常。最后会将游离对象或和依赖的名称匹配的 bean 作为结果进行返回。

总结

Spring 依赖解析会优先根据 @Value 注解进行解析,并且支持多种类型。对于类型为 Optional、ObjectFactory 的依赖 Spring 会将依赖包装后返回,其他类型又分为集合类型和单一类型,对于集合类型 Spring 查找对所有依赖后直接包装为对应的类型返回即可,对于单一类型 Spring 会优先考虑 primary、最高优先级、和所需 bean 名称匹配的 bean。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大鹏cool

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值