• Spring -Spring之依赖注入源码解析(下)


    之前Spring中的自动注入(byName,byType)@Autowired注解的工作原理以及源码分析,那么今天这节课,我们来分析还没讲完的,剩下的核心的方法:

    1. @Nullable
    2. Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
    3.   @Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException;

    该方法表示,传入一个依赖描述(DependencyDescriptor),该方法会根据该依赖描述从BeanFactory中找出对应的唯一的一个Bean对象。

    下面来分析一下DefaultListableBeanFactory中**resolveDependency()**方法的具体实现,具体流程图
    Spring中根据Type找Bean的流程| ProcessOn免费在线作图,在线流程图,在线思维导图

    findAutowireCandidates()实现

    根据类型找beanName的底层流程根据类型找beanName的底层流程| ProcessOn免费在线作图,在线流程图,在线思维导图
    对应执行流程图为依赖注入流程| ProcessOn免费在线作图,在线流程图,在线思维导图

    1. 找出BeanFactory中类型为type的所有的Bean的名字,注意是名字,而不是Bean对象,因为我们可以根据BeanDefinition就能判断和当前type是不是匹配,不用生成Bean对象
    2. 把resolvableDependencies中key为type的对象找出来并添加到result中
    3. 遍历根据type找出的beanName,判断当前beanName对应的Bean是不是能够被自动注入
    4. 先判断beanName对应的BeanDefinition中的autowireCandidate属性,如果为false,表示不能用来进行自动注入,如果为true则继续进行判断
    5. 判断当前type是不是泛型,如果是泛型是会把容器中所有的beanName找出来的,如果是这种情况,那么在这一步中就要获取到泛型的真正类型,然后进行匹配,如果当前beanName和当前泛型对应的真实类型匹配,那么则继续判断
    6. 如果当前DependencyDescriptor上存在@Qualifier注解,那么则要判断当前beanName上是否定义了Qualifier,并且是否和当前DependencyDescriptor上的Qualifier相等,相等则匹配
    7. 经过上述验证之后,当前beanName才能成为一个可注入的,添加到result中

    关于依赖注入中泛型注入的实现

    首先在Java反射中,有一个Type接口,表示类型,具体分类为:

    1. raw types:也就是普通Class
    2. parameterized types:对应ParameterizedType接口,泛型类型
    3. array types:对应GenericArrayType,泛型数组
    4. type variables:对应TypeVariable接口,表示类型变量,也就是所定义的泛型,比如T、K
    5. primitive types:基本类型,int、boolean

    大家可以好好看看下面代码所打印的结果:

    1. public class TypeTest<T> {
    2.  private int i;
    3.  private Integer it;
    4.  private int[] iarray;
    5.  private List list;
    6.  private List slist;
    7.  private List tlist;
    8.  private T t;
    9.  private T[] tarray;
    10.  public static void main(String[] args) throws NoSuchFieldException {
    11.   test(TypeTest.class.getDeclaredField("i"));
    12.   System.out.println("=======");
    13.   test(TypeTest.class.getDeclaredField("it"));
    14.   System.out.println("=======");
    15.   test(TypeTest.class.getDeclaredField("iarray"));
    16.   System.out.println("=======");
    17.   test(TypeTest.class.getDeclaredField("list"));
    18.   System.out.println("=======");
    19.   test(TypeTest.class.getDeclaredField("slist"));
    20.   System.out.println("=======");
    21.   test(TypeTest.class.getDeclaredField("tlist"));
    22.   System.out.println("=======");
    23.   test(TypeTest.class.getDeclaredField("t"));
    24.   System.out.println("=======");
    25.   test(TypeTest.class.getDeclaredField("tarray"));
    26.  }
    27.  public static void test(Field field) {
    28.   if (field.getType().isPrimitive()) {
    29.    System.out.println(field.getName() + "是基本数据类型");
    30.   } else {
    31.    System.out.println(field.getName() + "不是基本数据类型");
    32.   }
    33.   if (field.getGenericType() instanceof ParameterizedType) {
    34.    System.out.println(field.getName() + "是泛型类型");
    35.   } else {
    36.    System.out.println(field.getName() + "不是泛型类型");
    37.   }
    38.   if (field.getType().isArray()) {
    39.    System.out.println(field.getName() + "是普通数组");
    40.   } else {
    41.    System.out.println(field.getName() + "不是普通数组");
    42.   }
    43.   if (field.getGenericType() instanceof GenericArrayType) {
    44.    System.out.println(field.getName() + "是泛型数组");
    45.   } else {
    46.    System.out.println(field.getName() + "不是泛型数组");
    47.   }
    48.   if (field.getGenericType() instanceof TypeVariable) {
    49.    System.out.println(field.getName() + "是泛型变量");
    50.   } else {
    51.    System.out.println(field.getName() + "不是泛型变量");
    52.   }
    53.  }
    54. }

    Spring中,但注入点是一个泛型时,也是会进行处理的,比如:

    1. @Component
    2. public class UserService extends BaseService<OrderService, StockService> {
    3.  public void test() {
    4.   System.out.println(o);
    5.  }
    6. }
    7. public class BaseService<O, S> {
    8.  @Autowired
    9.  protected O o;
    10.  @Autowired
    11.  protected S s;
    12. }

    1. Spring扫描时发现UserService是一个Bean
    2. 那就取出注入点,也就是BaseService中的两个属性o、s
    3. 接下来需要按注入点类型进行注入,但是o和s都是泛型,所以Spring需要确定o和s的具体类型。
    4. 因为当前正在创建的是UserService的Bean,所以可以通过userService.getClass().getGenericSuperclass().getTypeName()获取到具体的泛型信息,比如com.zhouyu.service.BaseService
    5. 然后再拿到UserService的父类BaseService的泛型变量: for (TypeVariable> typeParameter : userService.getClass().getSuperclass().getTypeParameters()) { System._out_.println(typeParameter.getName()); }
    6. 通过上面两段代码,就能知道,o对应的具体就是OrderService,s对应的具体类型就是StockService
    7. 然后再调用oField.getGenericType()就知道当前field使用的是哪个泛型,就能知道具体类型了

    @Qualifier的使用

    定义两个注解:

    1. @Target({ElementType.TYPE, ElementType.FIELD})
    2. @Retention(RetentionPolicy.RUNTIME)
    3. @Qualifier("random")
    4. public @interface Random {
    5. }
    1. @Target({ElementType.TYPE, ElementType.FIELD})
    2. @Retention(RetentionPolicy.RUNTIME)
    3. @Qualifier("roundRobin")
    4. public @interface RoundRobin {
    5. }

    定义一个接口和两个实现类,表示负载均衡:

    1. public interface LoadBalance {
    2.  String select();
    3. }

    1. @Component
    2. @Random
    3. public class RandomStrategy implements LoadBalance {
    4.  @Override
    5.  public String select() {
    6.   return null;
    7.  }
    8. }
    1. @Component
    2. @RoundRobin
    3. public class RoundRobinStrategy implements LoadBalance {
    4.  @Override
    5.  public String select() {
    6.   return null;
    7.  }
    8. }

    使用:

    1. @Component
    2. public class UserService  {
    3.  @Autowired
    4.  @RoundRobin
    5.  private LoadBalance loadBalance;
    6.  public void test() {
    7.   System.out.println(loadBalance);
    8.  }
    9. }

    @Resource

    @Resource注解底层工作流程图:
    @Resource注解底层工作原理| ProcessOn免费在线作图,在线流程图,在线思维导图

  • 相关阅读:
    【VastbaseG100】 FATAL: The account has been locked.
    python对数据的处理合集——字典、列表...
    1. 数据结构
    不会metaclass你居然敢说自己会Python?
    VUE 项目组成逻辑(手写一个vue-cli)
    Haskell高阶函数(归并排序mergesort,map,filter)
    webpack -vite(Rollup )-Gulp (一)
    密码学系列之八:密码协议
    HSA-PEG-N3/azide 人血清白蛋白PEG叠氮,叠氮-聚乙二醇-人血清白蛋白
    mysql与磁盘的关系
  • 原文地址:https://blog.csdn.net/weixin_43874650/article/details/134322752