Spring依赖注入(DI)核心接口AutowireCandidateResolver深度分析,解析@Lazy、@Qualifier注解的原理【享学Spring】(上)

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: Spring依赖注入(DI)核心接口AutowireCandidateResolver深度分析,解析@Lazy、@Qualifier注解的原理【享学Spring】(上)

前言


关于AutowireCandidateResolver接口,可能绝大多数小伙伴都会觉得陌生。但若谈起@Autowired、@Primary、@Qualifier、@Value、@Lazy等注解,相信没有小伙伴是不知道的吧。


备注:@Primary这个注解是在解析bean定义时候处理的,解析成为isPrimary()从而在beanFactory里得到使用


在上篇文章:【小家Spring】使用@Async异步注解导致该Bean在循环依赖时启动报BeanCurrentlyInCreationException异常的根本原因分析,以及提供解决方案 有提到过可以使用@Autowired + @Lazy的方式来解决那个循环依赖问题,效果是它最终注入进去并不是容器内的代理对象(备注:是能够正常work的),有小伙伴有私聊我咋回事? 这篇文章中你可以找到答案~


AutowireCandidateResolver


用于确定特定的Bean定义是否符合特定的依赖项的候选者的策略接口。


这是这个接口类的Javadoc的描述,非常绕口、晦涩有木有???

此处我也先不要急着下定义了,毕竟我们的重点不是定义本身,而是现实。相信了解了它的工作原理,定义自在我心~


// @since 2.5   伴随着@Autowired体系出现
public interface AutowireCandidateResolver {
  // 判断给定的bean定义是否允许被依赖注入(bean定义的默认值都是true)
  default boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
    return bdHolder.getBeanDefinition().isAutowireCandidate();
  }
  // 给定的descriptor是否是必须的~~~
  // @since 5.0
  default boolean isRequired(DependencyDescriptor descriptor) {
    return descriptor.isRequired();
  }
  // QualifierAnnotationAutowireCandidateResolver对它有实现
  //  @since 5.1 此方法出现得非常的晚
  default boolean hasQualifier(DependencyDescriptor descriptor) {
    return false;
  }
  // 是否给一个建议值 注入的时候~~~QualifierAnnotationAutowireCandidateResolvert有实现
  // @since 3.0
  @Nullable
  default Object getSuggestedValue(DependencyDescriptor descriptor) {
    return null;
  }
  // 如果注入点injection point需要的话,就创建一个proxy来作为最终的解决方案ContextAnnotationAutowireCandidateResolver
  // @since 4.0
  @Nullable
  default Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, @Nullable String beanName) {
    return null;
  }
}


查看它的继承树:

image.png


层次特点非常明显:每一层都只有一个类,所以毫无疑问,最后一个实现类肯定是功能最全的了。


SimpleAutowireCandidateResolver


// @since 2.5
public class SimpleAutowireCandidateResolver implements AutowireCandidateResolver {
  @Override
  public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
    return bdHolder.getBeanDefinition().isAutowireCandidate();
  }
  @Override
  public boolean isRequired(DependencyDescriptor descriptor) {
    return descriptor.isRequired();
  }
  @Override
  @Nullable
  public Object getSuggestedValue(DependencyDescriptor descriptor) {
    return null;
  }
  @Override
  @Nullable
  public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, @Nullable String beanName) {
    return null;
  }
}


最简单的实现,适配器形式的存在,不可直接使用~


GenericTypeAwareAutowireCandidateResolver


从名字可以看出和泛型有关。Spring4.0后的泛型依赖注入主要是它来实现的,所以这个类也是Spring4.0后出现的


//@since 4.0 它能够根据泛型类型进行匹配~~~~  【泛型依赖注入】
public class GenericTypeAwareAutowireCandidateResolver extends SimpleAutowireCandidateResolver implements BeanFactoryAware {
  // 它能处理类型  毕竟@Autowired都是按照类型匹配的
  @Nullable
  private BeanFactory beanFactory;
  // 是否允许被依赖~~~
  // 因为bean定义里默认是true,绝大多数情况下我们不会修改它~~~
  // 所以继续执行:checkGenericTypeMatch 看看泛型类型是否能够匹配上
  // 若能够匹配上   这个就会被当作候选的Bean了~~~
  @Override
  public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
    // 如果bean定义里面已经不允许了  那就不往下走了  显然我们不会这么做
    if (!super.isAutowireCandidate(bdHolder, descriptor)) {
      // If explicitly false, do not proceed with any other checks...
      return false;
    }
    // 处理泛型依赖的核心方法~~~  也是本实现类的灵魂
    // 注意:这里还兼容到了工厂方法模式FactoryMethod
    // 所以即使你返回BaseDao<T>它是能够很好的处理好类型的~~~
    return checkGenericTypeMatch(bdHolder, descriptor);
  }
  ...
}


本实现类的主要任务就是解决了泛型依赖,此类虽然为实现类,但也不建议直接使用,因为功能还不完整~

QualifierAnnotationAutowireCandidateResolver


这个实现类非常非常的重要,它继承自GenericTypeAwareAutowireCandidateResolver,所以它不仅仅能处理org.springframework.beans.factory.annotation.Qualifier、@Value,还能够处理泛型依赖注入,因此功能已经很完善了~~~ 在Spring2.5之后都使用它来处理依赖关系~


Spring4.0之前它继承自SimpleAutowireCandidateResolver,Spring4.0之后才继承自GenericTypeAwareAutowireCandidateResolver


它不仅仅能够处理@Qualifier注解,也能够处理通过@Value注解解析表达式得到的suggested value,也就是说它还实现了接口方法getSuggestedValue();


getSuggestedValue()方法是Spring3.0后提供的,因为@Value注解是Spring3.0后提供的强大注解。

关于@Value注解的魅力,请参阅:【小家Spring】Spring中@Value注解有多强大?从原理层面去剖析为何它有如此大的“能耐“


// @since 2.5
public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwareAutowireCandidateResolver {
  // 支持的注解类型,默认支持@Qualifier和JSR-330的javax.inject.Qualifier注解
  private final Set<Class<? extends Annotation>> qualifierTypes = new LinkedHashSet<>(2);
  private Class<? extends Annotation> valueAnnotationType = Value.class;
  // 你可可以通过构造函数,增加你自定义的注解的支持~~~
  // 注意都是add  不是set
  public QualifierAnnotationAutowireCandidateResolver(Class<? extends Annotation> qualifierType) {
    Assert.notNull(qualifierType, "'qualifierType' must not be null");
    this.qualifierTypes.add(qualifierType);
  }
  public QualifierAnnotationAutowireCandidateResolver(Set<Class<? extends Annotation>> qualifierTypes) {
    Assert.notNull(qualifierTypes, "'qualifierTypes' must not be null");
    this.qualifierTypes.addAll(qualifierTypes);
  }
  // 后面讲的CustomAutowireConfigurer 它会调用这个方法来自定义注解
  public void addQualifierType(Class<? extends Annotation> qualifierType) {
    this.qualifierTypes.add(qualifierType);
  }
  //@Value注解类型Spring也是允许我们改成自己的类型的
  public void setValueAnnotationType(Class<? extends Annotation> valueAnnotationType) {
    this.valueAnnotationType = valueAnnotationType;
  }
  // 这个实现,比父类的实现就更加的严格了,区分度也就越高了~~~
  // checkQualifiers方法是本类的核心,灵魂
  // 它有两个方法getQualifiedElementAnnotation和getFactoryMethodAnnotation表名了它支持filed和方法
  @Override
  public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
    boolean match = super.isAutowireCandidate(bdHolder, descriptor);
    // 这里发现,及时父类都匹配上了,我本来还得再次校验一把~~~
    if (match) {
      // @Qualifier注解在此处生效  最终可能匹配出一个或者0个出来
      match = checkQualifiers(bdHolder, descriptor.getAnnotations());
      // 若字段上匹配上了还不行,还得看方法上的这个注解
      if (match) {
        // 这里处理的是方法入参们~~~~  只有方法有入参才需要继续解析
        MethodParameter methodParam = descriptor.getMethodParameter();
        if (methodParam != null) {
          Method method = methodParam.getMethod();
          // 这个处理非常有意思:methodParam.getMethod()表示这个入参它所属于的方法
          // 如果它不属于任何方法或者属于方法的返回值是void  才去看它头上标注的@Qualifier注解
          if (method == null || void.class == method.getReturnType()) {
            match = checkQualifiers(bdHolder, methodParam.getMethodAnnotations());
          }
        }
      }
    }
    return match;
  }
  ...
  protected boolean isQualifier(Class<? extends Annotation> annotationType) {
    for (Class<? extends Annotation> qualifierType : this.qualifierTypes) {
      if (annotationType.equals(qualifierType) || annotationType.isAnnotationPresent(qualifierType)) {
        return true;
      }
    }
    return false;
  }
  // 这里显示的使用了Autowired 注解,我个人感觉这里是不应该的~~~~ 毕竟已经到这一步了  应该脱离@Autowired注解本身
  // 当然,这里相当于是做了个fallback~~~还算可以接受吧
  @Override
  public boolean isRequired(DependencyDescriptor descriptor) {
    if (!super.isRequired(descriptor)) {
      return false;
    }
    Autowired autowired = descriptor.getAnnotation(Autowired.class);
    return (autowired == null || autowired.required());
  }
  // 标注的所有注解里  是否有@Qualifier这个注解~
  @Override
  public boolean hasQualifier(DependencyDescriptor descriptor) {
    for (Annotation ann : descriptor.getAnnotations()) {
      if (isQualifier(ann.annotationType())) {
        return true;
      }
    }
    return false;
  }
  // @since 3.0   这是本类的另外一个核心 解析@Value注解
  // 需要注意的是此类它不负责解析占位符啥的  只复杂把字符串返回
  // 最终是交给value = evaluateBeanDefinitionString(strVal, bd);它处理~~~
  @Override
  @Nullable
  public Object getSuggestedValue(DependencyDescriptor descriptor) {
    // 拿到value注解(当然不一定是@Value注解  可以自定义嘛)  并且拿到它的注解属性value值~~~  比如#{person}
    Object value = findValue(descriptor.getAnnotations());
    if (value == null) {
      // 相当于@Value注解标注在方法入参上 也是阔仪的~~~~~
      MethodParameter methodParam = descriptor.getMethodParameter();
      if (methodParam != null) {
        value = findValue(methodParam.getMethodAnnotations());
      }
    }
    return value;
  }
  ...
}


这个注解的功能已经非常强大了,Spring4.0之前都是使用的它去解决候选、依赖问题,但也不建议直接使用,因为下面这个,也就是它的子类更为强大~


相关文章
|
8天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
32 2
|
27天前
|
搜索推荐 Java Spring
Spring Filter深度解析
【10月更文挑战第21天】Spring Filter 是 Spring 框架中非常重要的一部分,它为请求处理提供了灵活的控制和扩展机制。通过合理配置和使用 Filter,可以实现各种个性化的功能,提升应用的安全性、可靠性和性能。还可以结合具体的代码示例和实际应用案例,进一步深入探讨 Spring Filter 的具体应用和优化技巧,使对它的理解更加全面和深入。
|
29天前
|
存储 安全 Java
|
1月前
|
Java Spring
Spring底层架构源码解析(三)
Spring底层架构源码解析(三)
113 5
|
1月前
|
XML Java 数据格式
Spring底层架构源码解析(二)
Spring底层架构源码解析(二)
|
1月前
|
XML Java 数据格式
Spring IOC容器的深度解析及实战应用
【10月更文挑战第14天】在软件工程中,随着系统规模的扩大,对象间的依赖关系变得越来越复杂,这导致了系统的高耦合度,增加了开发和维护的难度。为解决这一问题,Michael Mattson在1996年提出了IOC(Inversion of Control,控制反转)理论,旨在降低对象间的耦合度,提高系统的灵活性和可维护性。Spring框架正是基于这一理论,通过IOC容器实现了对象间的依赖注入和生命周期管理。
67 0
|
1月前
|
缓存 Java 程序员
Map - LinkedHashSet&Map源码解析
Map - LinkedHashSet&Map源码解析
70 0
|
1月前
|
算法 Java 容器
Map - HashSet & HashMap 源码解析
Map - HashSet & HashMap 源码解析
57 0
|
1月前
|
存储 Java C++
Collection-PriorityQueue源码解析
Collection-PriorityQueue源码解析
62 0
|
1月前
|
安全 Java 程序员
Collection-Stack&Queue源码解析
Collection-Stack&Queue源码解析
83 0

推荐镜像

更多