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

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


相关文章
|
3天前
|
数据可视化 前端开发 测试技术
接口测试新选择:Postman替代方案全解析
在软件开发中,接口测试工具至关重要。Postman长期占据主导地位,但随着国产工具的崛起,越来越多开发者转向更适合中国市场的替代方案——Apifox。它不仅支持中英文切换、完全免费不限人数,还具备强大的可视化操作、自动生成文档和API调试功能,极大简化了开发流程。
|
25天前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
4天前
|
人工智能 供应链 搜索推荐
中国CRM市场深度分析:主流供应商排名与特点解析
随着中国企业数字化转型的深入,CRM(客户关系管理)软件市场迅速发展,形成了多个优秀解决方案提供商。销售易、纷享销客、明源云客、金蝶云之家、简道云、红圈营销和爱客CRM等供应商各具特色。销售易在大型企业市场表现突出,提供全链路营销销售一体化及强大的AI能力;纷享销客以易用性和高性价比著称,适合中小企业;明源云客专注房地产行业,提供全流程解决方案;金蝶云之家与ERP系统深度整合,适合传统制造业;简道云是低代码平台,灵活性高;红圈营销专注零售业,支持全渠道营销;爱客CRM则主打智能营销功能。企业在选择CRM时需综合考虑实施难度、价格定位、技术支持等因素,并结合自身需求进行试用和调研,确保选择最适合
|
1月前
|
XML Java 数据格式
Spring Core核心类库的功能与应用实践分析
【12月更文挑战第1天】大家好,今天我们来聊聊Spring Core这个强大的核心类库。Spring Core作为Spring框架的基础,提供了控制反转(IOC)和依赖注入(DI)等核心功能,以及企业级功能,如JNDI和定时任务等。通过本文,我们将从概述、功能点、背景、业务点、底层原理等多个方面深入剖析Spring Core,并通过多个Java示例展示其应用实践,同时指出对应实践的优缺点。
62 14
|
2月前
|
测试技术 开发者 Python
使用Python解析和分析源代码
本文介绍了如何使用Python的`ast`模块解析和分析Python源代码,包括安装准备、解析源代码、分析抽象语法树(AST)等步骤,展示了通过自定义`NodeVisitor`类遍历AST并提取信息的方法,为代码质量提升和自动化工具开发提供基础。
100 8
|
1月前
|
调度 开发者
核心概念解析:进程与线程的对比分析
在操作系统和计算机编程领域,进程和线程是两个基本而核心的概念。它们是程序执行和资源管理的基础,但它们之间存在显著的差异。本文将深入探讨进程与线程的区别,并分析它们在现代软件开发中的应用和重要性。
63 4
|
2月前
|
前端开发 Java 开发者
Spring MVC中的请求映射:@RequestMapping注解深度解析
在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的关键,它将HTTP请求映射到相应的处理器方法上。本文将深入探讨`@RequestMapping`注解的工作原理、使用方法以及最佳实践,为开发者提供一份详尽的技术干货。
174 2
|
2月前
|
前端开发 Java Spring
探索Spring MVC:@Controller注解的全面解析
在Spring MVC框架中,`@Controller`注解是构建Web应用程序的基石之一。它不仅简化了控制器的定义,还提供了一种优雅的方式来处理HTTP请求。本文将全面解析`@Controller`注解,包括其定义、用法、以及在Spring MVC中的作用。
69 2
|
Java Spring
Spring的qualifier标签
@Autowired是根据类型进行自动装配的。如果当Spring上下文中存在不止一个UserDao类型的bean时,就会抛出BeanCreationException异常;如果Spring上下文中不存在UserDao类型的bean,也会抛出BeanCreationException异常。
1554 0
|
3天前
|
XML JavaScript Java
SpringBoot集成Shiro权限+Jwt认证
本文主要描述如何快速基于SpringBoot 2.5.X版本集成Shiro+JWT框架,让大家快速实现无状态登陆和接口权限认证主体框架,具体业务细节未实现,大家按照实际项目补充。
31 11

推荐镜像

更多