• Spring: @Autowired注解原理解析



    一、用法

    构造函数注入:

    public Class Outer {
     private Inner inner;
     @Autowired
     public Outer(Inner inner) {
      this.inner = inner;
     }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    属性注入:

    public Class Outer {
     @Autowired
     private Inner inner;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    方法注入:

    public Class Outer {
     private Inner inner;
     public Inner getInner() {
      return inner;
     }
     @Autowired
     public void setInner(Inner inner) {
      this.inner = inner;
     }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    二、原理解析

    如果我们自己设计@Autowired,我们应该怎么实现?我想做法还是比较简单的

    • 1.通过反射查找bean的class下所有注解了@Autowired的字段和方法
    • 2.获取到字段,通过getBean(字段)获取到对应bean,然后再通过反射调用field的set将bean注入

    AutowiredAnnotationBeanPostProcessor类是@Autowired的具体实现类
    在这里插入图片描述

    发现实际有机会介入bean的创建操作只有可能是后置处理器,用于后置处理的有3个方法,其中一个过时不用,分别是postProcessMergedBeanDefinition、postProcessProperties后置处理,我们再看一下这2个方法的具体代码

    public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
      implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
     ...
     @Override
     public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
      // 1. 寻找bean中所有被@Autowired注释的属性,并将属性封装成InjectedElement类型
      InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
      metadata.checkConfigMembers(beanDefinition);
     }
     ...
     @Override
     public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
      // 1. 寻找通过@Autowired注解的属性或者方法
      InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
      try {
       // 2. 注入
       metadata.inject(bean, beanName, pvs);
      }
      catch (BeanCreationException ex) {
       throw ex;
      }
      catch (Throwable ex) {
       throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
      }
      return pvs;
     }
     ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    跟我们的猜想是一样的,首先先找出所有注解了@Autowired的属性或者方法,然后进行注入,当然postProcessMergedBeanDefinition后置处理器的调用肯定是在postProcessProperties之前的,这里我们回顾一下spring bean的创建过程。

    在这里插入图片描述

    1. 查找所有@Autowired

    // 寻找bean中所有被@Autowired注释的属性,并将属性封装成InjectedElement类型
    InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
    private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
      // Fall back to class name as cache key, for backwards compatibility with custom callers.
      // 获取缓存的key值,一般以beanName做key
      String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
      // Quick check on the concurrent map first, with minimal locking.
      // 从缓存中获取metadata
      InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
      // 检测metadata是否需要更新
      if (InjectionMetadata.needsRefresh(metadata, clazz)) {
       synchronized (this.injectionMetadataCache) {
        metadata = this.injectionMetadataCache.get(cacheKey);
        if (InjectionMetadata.needsRefresh(metadata, clazz)) {
         if (metadata != null) {
          metadata.clear(pvs);
         }
         // 通过clazz类,查找所有@Autowired的属性或者方法,并封装成InjectionMetadata类型
         metadata = buildAutowiringMetadata(clazz);
         // 将metadata加入缓存
         this.injectionMetadataCache.put(cacheKey, metadata);
        }
       }
      }
      return metadata;
     }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    继续跟踪核心代码buildAutowiringMetadata(clazz)

     private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
      // 查看clazz是否有Autowired注解
      if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
       return InjectionMetadata.EMPTY;
      }
      // 这里需要注意AutowiredFieldElement,AutowiredMethodElement均继承了InjectionMetadata.InjectedElement
      // 因此这个列表是可以保存注解的属性和被注解的方法的
      List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
      Class<?> targetClass = clazz;
      // 1. 通过do while循环,递归的往直接继承的父类寻找@Autowired
      do {
       final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
       // 2. 通过反射,获取所有属性,doWithLocalFields则是循环的对每个属性应用以下匿名方法
       ReflectionUtils.doWithLocalFields(targetClass, field -> {
        // 判断当前field属性是否含有@Autowired的注解
        MergedAnnotation<?> ann = findAutowiredAnnotation(field);
        if (ann != null) {
         // 返回该属性在类中的修饰符,如果等于static常量,则抛出异常,@Autowired不允许注解在静态属性上
         if (Modifier.isStatic(field.getModifiers())) {
          if (logger.isInfoEnabled()) {
           logger.info("Autowired annotation is not supported on static fields: " + field);
          }
          return;
         }
         // @Autowired有required属性,获取required的值,默认为true
         boolean required = determineRequiredStatus(ann);
         // 3. 将field封装成InjectedElement,并添加到集合中,这里用的是AutowiredFieldElement
         currElements.add(new AutowiredFieldElement(field, required));
        }
       });
       // 4. @Autowired可以注解在方法上
       ReflectionUtils.doWithLocalMethods(targetClass, method -> {
        Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
        if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
         return;
        }
        MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
        if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
         if (Modifier.isStatic(method.getModifiers())) {
          if (logger.isInfoEnabled()) {
           logger.info("Autowired annotation is not supported on static methods: " + method);
          }
          return;
         }
         if (method.getParameterCount() == 0) {
          if (logger.isInfoEnabled()) {
           logger.info("Autowired annotation should only be used on methods with parameters: " +
             method);
          }
         }
         boolean required = determineRequiredStatus(ann);
         PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
         // 5. 将方法封装成InjectedElement,并添加到集合中,这里用的是AutowiredMethodElement
         currElements.add(new AutowiredMethodElement(method, required, pd));
        }
       });
       elements.addAll(0, currElements);
       // 返回直接继承的父类
       targetClass = targetClass.getSuperclass();
      }
      // 如果父类不为空则需要把父类的@Autowired属性或方法也找出
      while (targetClass != null && targetClass != Object.class);
      // 6. new InjectionMetadata(clazz, elements),将找到的所有的待注入属性或方法生成metadata返回
      return InjectionMetadata.forElements(elements, clazz);
     }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 外层 do … while … 的循环被用于递归的查找父类的@Autowired属性或方法
    • 通过反射的方式获取到所有属性并循环验证每一个属性是否被@Autowired注解
    • 将查找到包含@Autowired注解的filed封装成AutowiredFieldElement,加入到列表中
    • 循环查找在方法上的注解
    • 将找到的方法封装成AutowiredMethodElement,并加入列表

    这里需要特别强调一点,InjectedElement被AutowiredFieldElement、AutowiredMethodElement所继承,他们都有各自的inject函数,实现各自的注入。因此改ArrayList elements是拥有2种类型的属性

    2. 注入

    // 注入
    metadata.inject(bean, beanName, pvs);
     public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
      // 获取所有需要被注入的元素
      Collection<InjectedElement> checkedElements = this.checkedElements;
      Collection<InjectedElement> elementsToIterate =
        (checkedElements != null ? checkedElements : this.injectedElements);
      // 迭代的元素不为空
      if (!elementsToIterate.isEmpty()) {
       for (InjectedElement element : elementsToIterate) {
        if (logger.isTraceEnabled()) {
         logger.trace("Processing injected element of bean '" + beanName + "': " + element);
        }
        // 循环注入,这里有可能是AutowiredFieldElement也可能AutowiredMethodElement,因此调用的inject是2个不同的方法
        element.inject(target, beanName, pvs);
       }
      }
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    利用for循环,遍历刚刚我们查到到的elements列表,进行注入。

    在这里的代码当中我们也可以看到,是inject也使用了反射技术并且依然是分成字段和方法去处理的。在代码里面也调用了makeAccessible这样的可以称之为暴力破解的方法,但是反射技术本就是为框架等用途设计的,这也无可厚非。

    在上面有特别提醒,这里的element有可能是AutowiredFieldElement类型、或AutowiredMethodElement类型。各自代表@Autowired注解在属性上、以及注解在方法上的2种不同元素。因此他们调用的element.inject(target, beanName, pvs);也是不一样的

    3. 字段注入(AutowiredFieldElement)

     private class AutowiredFieldElement extends InjectionMetadata.InjectedElement {
      @Override
      protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
       Field field = (Field) this.member;
       Object value;
       if (this.cached) {
        value = resolvedCachedArgument(beanName, this.cachedFieldValue);
       }
       else {
        // 专门用于注入的包装类,包装构造函数参数,方法参数或字段
        DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
        // 设置class
        desc.setContainingClass(bean.getClass());
        // 需要被自动注入的beanNames,这里只有可能 = 1,方法注入时才有可能为多个
        Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
        Assert.state(beanFactory != null, "No BeanFactory available");
        TypeConverter typeConverter = beanFactory.getTypeConverter();// 获取类型转换器
        try {
         // 通过beanFactory获取属性对应的值,比如需要调用getBean("b")获取依赖的属性单例,并且通过自动转型转为需要的类型
         value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
        }
        catch (BeansException ex) {
         throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
        }
        synchronized (this) {
         if (!this.cached) {
          if (value != null || this.required) {
           this.cachedFieldValue = desc;
           // 注册依赖,
           registerDependentBeans(beanName, autowiredBeanNames);
           // 因为是属性注入,因此这里只有可能等于1
           if (autowiredBeanNames.size() == 1) {
            String autowiredBeanName = autowiredBeanNames.iterator().next();
            if (beanFactory.containsBean(autowiredBeanName) &&
              beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
             // 缓存当前value
             this.cachedFieldValue = new ShortcutDependencyDescriptor(
               desc, autowiredBeanName, field.getType());
            }
           }
          }
          else {
           this.cachedFieldValue = null;
          }
          this.cached = true;
         }
        }
       }
       if (value != null) {
        // 通过反射,将value值设置到bean中
        ReflectionUtils.makeAccessible(field);
        field.set(bean, value);
       }
      }
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    上方大部分的工作都在做待注入bean的获取以及类型的转换,如果深究下去可以再把spring Ioc讲一遍,但是核心还是getBean(字段)获取到对应bean…我们这里就关心核心的语句,就是这2句

    if (value != null) {
        // 通过反射,将value值设置到bean中
        ReflectionUtils.makeAccessible(field);
        field.set(bean, value);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    spring通过反射的方式,调用field的set进行属性的注入

    4. 方法注入(AutowiredMethodElement)

     private class AutowiredMethodElement extends InjectionMetadata.InjectedElement {
      @Override
      protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
       if (checkPropertySkipping(pvs)) {
        return;
       }
       // @Autowired标注在方法上
       Method method = (Method) this.member;
       Object[] arguments;
       if (this.cached) {
        // Shortcut for avoiding synchronization...
        // 有缓存
        arguments = resolveCachedArguments(beanName);
       }
       else {
        // 没缓存,直接获取方法上所有的参数
        int argumentCount = method.getParameterCount();
        arguments = new Object[argumentCount];
        DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
        Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
        Assert.state(beanFactory != null, "No BeanFactory available");
        TypeConverter typeConverter = beanFactory.getTypeConverter();
        // 循环所有参数
        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 {
          // 通过beanFactory,获取代注入的bean,并进行类型转换
          Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
          if (arg == null && !this.required) {
           arguments = null;
           break;
          }
          arguments[i] = arg;
         }
         catch (BeansException ex) {
          throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
         }
        }
        synchronized (this) {
         if (!this.cached) {
          if (arguments != null) {
           DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
           // 注册依赖
           registerDependentBeans(beanName, autowiredBeans);
           // 如果自动注入的个数 = 参数个数,则缓存
           if (autowiredBeans.size() == argumentCount) {
            Iterator<String> it = autowiredBeans.iterator();
            Class<?>[] paramTypes = method.getParameterTypes();
            for (int i = 0; i < paramTypes.length; i++) {
             String autowiredBeanName = it.next();
             if (beanFactory.containsBean(autowiredBeanName) &&
               beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
              // 缓存
              cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
                descriptors[i], autowiredBeanName, paramTypes[i]);
             }
            }
           }
           // 缓存方法
           this.cachedMethodArguments = cachedMethodArguments;
          }
          else {
           this.cachedMethodArguments = null;
          }
          this.cached = true;
         }
        }
       }
       if (arguments != null) {
        try {
         // 反射调用注入方法,将获取到的所有bean作为参数
         ReflectionUtils.makeAccessible(method);
         method.invoke(bean, arguments);
        }
        catch (InvocationTargetException ex) {
         throw ex.getTargetException();
        }
       }
      }
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83

    这里与属性注入最大的区别在于,@Autowired注解在方法上,方法可以拥有多个参数,因此这里需要通过循环将一个个获取,而获取bean的方式于上面一样,本质都是通过getBean获取。

    而核心语句还是2句

    // 反射调用注入方法,将获取到的所有bean作为参数
    ReflectionUtils.makeAccessible(method);
    method.invoke(bean, arguments);
    
    
    • 1
    • 2
    • 3
    • 4

    与属性注入不同的是,当@Autowired注解在方法上,例如我们注解在setter方法上,则只需要直接调用该setter方法将参数数组传入即可以,即使用invoke触发方法,具体属性赋值的过程在setter方法中由用户自行编写

    总结

    以上,就是@Autowire注解实现逻辑的全部分析。结合源代码再看一遍的话,会更加清楚一点。下面是spring容器如何实现@AutoWired自动注入的过程的图:
    在这里插入图片描述
    总结起来一句话:使用@Autowired注入的bean对于目标类来说,从代码结构上来讲也就是一个普通的成员变量,@Autowired和spring一起工作,通过反射为这个成员变量赋值,也就是将其赋为期望的类实例。另外,关注Java知音公众号,回复“后端面试”,送你一份面试题宝典!

    其他

    参考:https://www.jb51.net/article/252958.htm

  • 相关阅读:
    在 Windows 平台上启动 MATLAB
    解锁互联网安全的新钥匙:JWT(JSON Web Token)
    前端SVG的学习
    【超好懂的比赛题解】第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(济南)
    JP《乡村振兴振兴战略下传统村落文化旅游设计》许少辉书香续,山水长
    以“新IT”助“数智融合”,联想推开“智能化转型”下半场的大门
    Java 中关于字符串拼接替换的常用方法
    关于POI包处理excel方法详解 (一)
    论文阅读(一)城市干道分段绿波协调控制模型研究
    Webpack
  • 原文地址:https://blog.csdn.net/zhanggqianglovec/article/details/126154584