【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注解
继承图如上
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.Qualifier或javax.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实例 - 最后基于反射调用目标方法,完成属性注入