【Spring】深入解析 bean 的属性填充 三 AutowireCandidateResolver

236 阅读4分钟

【Spring】深入解析 bean 的属性填充 三 AutowireCandidateResolver

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

前言

结合之前的章节我们已经了解到:获取指定属性的备选 bean实例 时,会委托给 AutowireCandidateResolver 来处理

AutowireCandidateResolver,根据类名也能理解:自动注入备选解析器,此组类是专门用来解析指定属性对应的备选实例的

AutowireCandidateResolver

public interface AutowireCandidateResolver {

	// 目标 BeanDefinition 是否备选
	// 默认实现就是基于 BeanDefinition#isAutowireCandidate,默认 true
	default boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
		return bdHolder.getBeanDefinition().isAutowireCandidate();
	}

	// 是否必须注入,默认基于 descriptor.isRequired()
	default boolean isRequired(DependencyDescriptor descriptor) {
		return descriptor.isRequired();
	}

	// 指定 DependencyDescriptor 是否被限定符(比如 @Qualifier)修饰
	default boolean hasQualifier(DependencyDescriptor descriptor) {
		return false;
	}

	// @Value 注解解析
	@Nullable
	default Object getSuggestedValue(DependencyDescriptor descriptor) {
		return null;
	}

	// 略
	@Nullable
	default Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, @Nullable String beanName) {
		return null;
	}

	// clone
	default AutowireCandidateResolver cloneIfNecessary() {
		return BeanUtils.instantiateClass(getClass());
	}

}

定义了如上方法:

  • 其中上一章节主要基于 isAutowireCandidate 来进一步筛选备选实例
  • getSuggestedValue 方法用于解析 @Value 注解

AutowireCandidateResolver
继承图如上

SimpleAutowireCandidateResolver

最基础的实现,与接口提供的默认实现基本无二,略

GenericTypeAwareAutowireCandidateResolver

	@Override
	public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
		// 父类是基于 BeanDefinition#isAutowireCandidate 判断
		if (!super.isAutowireCandidate(bdHolder, descriptor)) {
			return false;
		}

		// 基于泛型检查
		return checkGenericTypeMatch(bdHolder, descriptor);
	}

SimpleAutowireCandidateResolver 的子类,主要拓展了 isAutowireCandidate 方法:

  • 基于泛型注入的能力,就是它提供的,在基于父类 isAutowireCandidate 筛选后,会交给 checkGenericTypeMatch 方法再次筛选
  • 此处主要进行了 泛型匹配,比如之前示例中针对 GenericPOJO<Integer, Integer> integerGenericPOJO 属性的注入,便会精确匹配
  • checkGenericTypeMatch 方法不深入解读但提出如下细节:针对诸如之前示例中 @Bean 的诸如方式,其方法返回类型必须明确声明泛型类型就像这样 public GenericPOJO<Integer, Integer> integerGenericPOJO() {...},而不仅仅是返回对应结果,否则也是无法精确匹配的
  • 不难理解,对于非精确匹配的泛型属性,若容器中存在多个泛型示例且不用集合接收,则会报错

QualifierAnnotationAutowireCandidateResolver

核心实现类,拓展了 @Qualifier 注解相关匹配逻辑,诸如示例中 @Qualifier("b") 修饰属性的注入就由此类完成

	@Override
	public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
		boolean match = super.isAutowireCandidate(bdHolder, descriptor);

		/**
		 * 基于 @Qualifier 注解的校验
		 * 1)同时会作为 元注解 校验
		 * 2)可以简单的理解为 value 属性与 beanName 的匹配
		 */
		if (match) {
			match = checkQualifiers(bdHolder, descriptor.getAnnotations());
			// ...
		}
		return match;
	}

拓展了 isAutowireCandidate,在基类的基础上增加了 @Qualifier 注解匹配相关逻辑:

  • 此处可以简单的理解为是 @Qualifier 注解的 value 属性与 beanName 的匹配(包括别名),该用途最为广泛
  • 还支持将 @Qualifier 作为 元注解 进行解析,也就是说,被 @Qualifier 注解修饰的注解也会起到 限定符 的效果,比如示例中的 @MyQualifier("b") 属性
	@Override
	public boolean isRequired(DependencyDescriptor descriptor) {
		if (!super.isRequired(descriptor)) {
			return false;
		}

		// 支持解析 @Autowired 注解的 required 属性
		Autowired autowired = descriptor.getAnnotation(Autowired.class);
		return (autowired == null || autowired.required());
	}

拓展了基类的 isRequired 方法:

  • 支持 @Autowired 注解的 required 属性解析
  • 对于 required = false 的属性,没有对应的备选实例不再抛出异常,默认 true
	@Override
	public boolean hasQualifier(DependencyDescriptor descriptor) {
		for (Annotation ann : descriptor.getAnnotations()) {
			if (isQualifier(ann.annotationType())) {
				return true;
			}
		}
		return false;
	}

指定 DependencyDescriptor 是否被限定符修饰:

  • 即解析指定元素是否被 org.springframework.beans.factory.annotation.Qualifierjavax.inject.Qualifier 注解修饰
  • 后者还需要额外导包,所以默认使用前者就好了
	@Override
	@Nullable
	public Object getSuggestedValue(DependencyDescriptor descriptor) {
		Object value = findValue(descriptor.getAnnotations());
		if (value == null) {
			MethodParameter methodParam = descriptor.getMethodParameter();
			if (methodParam != null) {
				value = findValue(methodParam.getMethodAnnotations());
			}
		}
		return value;
	}

解析 @Value 注解的 value 属性

ContextAnnotationAutowireCandidateResolver

最终实现类,实现了 getLazyResolutionProxyIfNecessary 方法,我们使用的 Spring 容器中,一般使用的就是它,注册代码见 org.springframework.context.annotation.AnnotationConfigUtils

总结

备选实例的筛选主要基于 AutowireCandidateResolver 完成,容器中对应的便是 ContextAnnotationAutowireCandidateResolver(在后续 ApplicationContext 相关文章会介绍),因此对备选实例的筛选支持 泛型精确匹配 限定符匹配

至此,文章最开头给出配置类的各种注入情况也就都可以理解了

AutowiredMethodElement#inject

	@Override
	protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
		
		// 是否跳过
		if (checkPropertySkipping(pvs)) {
			return;
		}
		Method method = (Method) this.member;
		Object[] arguments;
		
		// 缓存获取
		if (this.cached) {
			// Shortcut for avoiding synchronization...
			arguments = resolveCachedArguments(beanName);
		}
		else {
			
			// ...
			
			// 对于方法参数依次 beanFactory.resolveDependency
			for (int i = 0; i < arguments.length; i++) {
				MethodParameter methodParam = new MethodParameter(method, i);
				DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
				currDesc.setContainingClass(bean.getClass());
				descriptors[i] = currDesc;
				try {
					Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
					if (arg == null && !this.required) {
						arguments = null;
						break;
					}
					arguments[i] = arg;
				}
				catch (BeansException ex) {
					
				}
			}
			
			// 缓存相关...
			
		}
		// 最后带上参数 method.invoke
		if (arguments != null) {
			try {
				ReflectionUtils.makeAccessible(method);
				method.invoke(bean, arguments);
			}
			catch (InvocationTargetException ex) {
				throw ex.getTargetException();
			}
		}
	}

文章最后给出基于方法的属性注入代码即 AutowiredMethodElement#inject,至此这里的代码也就不难理解了:

  • 基于 beanFactory.resolveDependency 获取方法参数对应的 bean实例
  • 最后基于反射调用目标方法,完成属性注入