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

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: 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之前都是使用的它去解决候选、依赖问题,但也不建议直接使用,因为下面这个,也就是它的子类更为强大~


相关文章
|
24天前
|
存储 缓存 算法
HashMap深度解析:从原理到实战
HashMap,作为Java集合框架中的一个核心组件,以其高效的键值对存储和检索机制,在软件开发中扮演着举足轻重的角色。作为一名资深的AI工程师,深入理解HashMap的原理、历史、业务场景以及实战应用,对于提升数据处理和算法实现的效率至关重要。本文将通过手绘结构图、流程图,结合Java代码示例,全方位解析HashMap,帮助读者从理论到实践全面掌握这一关键技术。
73 13
|
2月前
|
运维 持续交付 云计算
深入解析云计算中的微服务架构:原理、优势与实践
深入解析云计算中的微服务架构:原理、优势与实践
82 1
|
17天前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
10天前
|
存储 物联网 大数据
探索阿里云 Flink 物化表:原理、优势与应用场景全解析
阿里云Flink的物化表是流批一体化平台中的关键特性,支持低延迟实时更新、灵活查询性能、无缝流批处理和高容错性。它广泛应用于电商、物联网和金融等领域,助力企业高效处理实时数据,提升业务决策能力。实践案例表明,物化表显著提高了交易欺诈损失率的控制和信贷审批效率,推动企业在数字化转型中取得竞争优势。
54 14
|
16天前
|
存储 Java 应用服务中间件
【Spring】IoC和DI,控制反转,Bean对象的获取方式
IoC,DI,控制反转容器,Bean的基本常识,类注解@Controller,获取Bean对象的常用三种方式
|
19天前
|
网络协议 安全 网络安全
探索网络模型与协议:从OSI到HTTPs的原理解析
OSI七层网络模型和TCP/IP四层模型是理解和设计计算机网络的框架。OSI模型包括物理层、数据链路层、网络层、传输层、会话层、表示层和应用层,而TCP/IP模型则简化为链路层、网络层、传输层和 HTTPS协议基于HTTP并通过TLS/SSL加密数据,确保安全传输。其连接过程涉及TCP三次握手、SSL证书验证、对称密钥交换等步骤,以保障通信的安全性和完整性。数字信封技术使用非对称加密和数字证书确保数据的机密性和身份认证。 浏览器通过Https访问网站的过程包括输入网址、DNS解析、建立TCP连接、发送HTTPS请求、接收响应、验证证书和解析网页内容等步骤,确保用户与服务器之间的安全通信。
74 1
|
2月前
|
测试技术 开发者 Python
使用Python解析和分析源代码
本文介绍了如何使用Python的`ast`模块解析和分析Python源代码,包括安装准备、解析源代码、分析抽象语法树(AST)等步骤,展示了通过自定义`NodeVisitor`类遍历AST并提取信息的方法,为代码质量提升和自动化工具开发提供基础。
84 8
|
1月前
|
调度 开发者
核心概念解析:进程与线程的对比分析
在操作系统和计算机编程领域,进程和线程是两个基本而核心的概念。它们是程序执行和资源管理的基础,但它们之间存在显著的差异。本文将深入探讨进程与线程的区别,并分析它们在现代软件开发中的应用和重要性。
62 4
|
2月前
|
前端开发 Java 开发者
Spring MVC中的请求映射:@RequestMapping注解深度解析
在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的关键,它将HTTP请求映射到相应的处理器方法上。本文将深入探讨`@RequestMapping`注解的工作原理、使用方法以及最佳实践,为开发者提供一份详尽的技术干货。
159 2
|
2月前
|
前端开发 Java Spring
探索Spring MVC:@Controller注解的全面解析
在Spring MVC框架中,`@Controller`注解是构建Web应用程序的基石之一。它不仅简化了控制器的定义,还提供了一种优雅的方式来处理HTTP请求。本文将全面解析`@Controller`注解,包括其定义、用法、以及在Spring MVC中的作用。
67 2

推荐镜像

更多