• Spring注解之@Autowired


    前言

        说起Spring的@Autowired注解,想必大家已经熟悉的不能再熟悉了。本文就针对此最常用的注解,梳理一下它的功能和原理,争取从源码的角度将此注解讲通,如有写的不准确的地方,欢迎各位园友拍砖。

    注:此篇博文基于Spring5.1.10.RELEASE,SpringBoot2.1.9.RELEASE

    正文

        首先看一下@Autowired注解的源码

     1 package org.springframework.beans.factory.annotation;
     2 
     3 import java.lang.annotation.Documented;
     4 import java.lang.annotation.ElementType;
     5 import java.lang.annotation.Retention;
     6 import java.lang.annotation.RetentionPolicy;
     7 import java.lang.annotation.Target;
     8 
     9 @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
    10 @Retention(RetentionPolicy.RUNTIME)
    11 @Documented
    12 public @interface Autowired {
    13 
    14     /**
    15      * Declares whether the annotated dependency is required.
    16      * <p>Defaults to {@code true}.
    17      */
    18     boolean required() default true;
    19 
    20 }

        可以看到,此注解运行时生效,且适用范围很广,从构造器,到方法,到参数、属性、注解,都可以加上@Autowired注解。它还有一个属性required,此属性用于控制如果找不到要依赖注入的对象时是否报错,默认true即默认找不到要注入的对象时会报错。下面我们慢慢梳理,将@Autowired的使用场景一一罗列出来。

    一、普通用法,依赖注入成员变量

    下面将要用的测试类贴出来,首先是接口

    1 package com.mybokeyuan.springAutowiredDemo;
    2 
    3 public interface IndexInterface {
    4 }

    再就是两个子类

    1 package com.mybokeyuan.springAutowiredDemo;
    2 
    3 import org.springframework.stereotype.Component;
    4 
    5 @Component
    6 public class IndexService implements IndexInterface{
    7 
    8 }
    1 package com.mybokeyuan.springAutowiredDemo;
    2 
    3 import org.springframework.stereotype.Component;
    4 
    5 @Component
    6 public class OtherIndexService implements IndexInterface{
    7     
    8 }

    核心类(后续的各种场景演示均只基于此类进行改动)

     1 package com.mybokeyuan.springAutowiredDemo;
     2 
     3 import org.springframework.beans.factory.annotation.Autowired;
     4 import org.springframework.stereotype.Component;
     5 
     6 @Component
     7 public class MyService {
     8 
     9     @Autowired
    10     private IndexService indexService;
    11 
    12 }

    扫描配置类

    1 package com.mybokeyuan.springAutowiredDemo;
    2 
    3 import org.springframework.context.annotation.ComponentScan;
    4 import org.springframework.context.annotation.Configuration;
    5 
    6 @Configuration
    7 @ComponentScan("com.mybokeyuan.springAutowiredDemo")
    8 public class AutowiredConfig {
    9 }

    main方法类

     1 package com.mybokeyuan.springAutowiredDemo.client;
     2 
     3 import com.mybokeyuan.springAutowiredDemo.AutowiredConfig;
     4 import com.mybokeyuan.springAutowiredDemo.MyService;
     5 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
     6 
     7 public class DemoClientTest {
     8     public static void main(String[] args) {
     9         AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AutowiredConfig.class);
    10         System.out.println(ac.getBean(MyService.class));
    11 
    12     }
    13 }

    运行main方法时,如果在第10行打了断点,会看到MyService中的indexService属性已经依赖注入了值,这是我们最常使用@Autowired注解的场景。

    二、依赖注入方法

     MyService类如下所示

     1 package com.mybokeyuan.springAutowiredDemo;
     2 
     3 import org.springframework.beans.factory.annotation.Autowired;
     4 import org.springframework.context.ApplicationContext;
     5 import org.springframework.stereotype.Component;
     6 
     7 import java.util.List;
     8 
     9 @Component
    10 public class MyService {
    11 
    12     private IndexService indexService;
    13 
    14     @Autowired
    15     public void getIndexInterf (IndexService index) {
    16         indexService = index;
    17     }
    18 
    19     @Autowired
    20     private ApplicationContext applicationContext;
    21 
    22 }

    运行main方法后,会发现该类中的indexService完成了注入,这样的用法类似于set方法的功能。并且可以看到,applicationContext也注入了。所以往后就不要用ApplicationContextAware了,直接@Autowired轻快便捷的达到目的。

    三、构造方法注入参数

     MyService类如下所示:

     1 package com.mybokeyuan.springAutowiredDemo;
     2 
     3 import org.springframework.beans.factory.annotation.Autowired;
     4 import org.springframework.stereotype.Component;
     5 
     6 import java.util.List;
     7 
     8 @Component
     9 public class MyService {
    10 
    11 
    12     private IndexService indexService;
    13 
    14     private List<IndexInterface> indexList;
    15 
    16     @Autowired
    17     public MyService (List<IndexInterface> indexList, IndexService indexService) {
    18         this.indexList = indexList;
    19         this.indexService = indexService;
    20     }
    21 }

            运行后会发现成员变量indexList和indexService中已经注入了值。此处需要注意一点,如果有两个自定义构造方法,两个都没加@Autowired注解,则会报错,因为Spring不知道你要用哪个构造方法初始化;

    如果只有一个构造方法加了@Autowired注解,那么就会用这个构造方法初始化;同理,如果有多个构造方法都加了@Autowired注解,那么还是会报错。

    四、注入Map、List等集合

     在【一、普通用法】中的MyService里添加几个成员变量,如下所示:

     1 package com.mybokeyuan.springAutowiredDemo;
     2 
     3 import org.springframework.beans.factory.annotation.Autowired;
     4 import org.springframework.stereotype.Component;
     5 
     6 import java.util.List;
     7 import java.util.Map;
     8 import java.util.Set;
     9 
    10 @Component
    11 public class MyService {
    12     
    13     @Autowired
    14     private IndexService indexService;
    15 
    16     @Autowired
    17     private List<IndexInterface> indexList;
    18 
    19     @Autowired
    20     private Map<String, IndexInterface> indexMap;
    21 
    22     @Autowired
    23     private Set<IndexInterface> indexSet;
    24 }

    再次运行main方法,在断点中可以看到从Spring中获取到的MyService对象中,已经完成了对后面三个集合的依赖注入,如下图所示:

    可以看到,IndexInterface接口的两个实现类全部注入到了集合中,且Map里面的key默认就是两个实现类各自的beanName。

    五、源码分析

            看了上面的各种使用场景,想必大家会对这个最熟悉的注解有了一丝陌生的感觉,不过不要紧,下面咱们慢慢来脱下TA的神秘衣服,对ta重新熟悉起来。我这里是以下面的MyService类为例子进行的源码debug分析。

     1 package com.mybokeyuan.springAutowiredDemo;
     2 
     3 import org.springframework.beans.factory.annotation.Autowired;
     4 import org.springframework.context.ApplicationContext;
     5 import org.springframework.stereotype.Component;
     6 
     7 import java.util.List;
     8 
     9 @Component
    10 public class MyService {
    11 
    12 
    13     private IndexService indexService;
    14 
    15     private List<IndexInterface> indexList;
    16 
    17     @Autowired
    18     public void getIndexInterf (IndexService index) {
    19         indexService = index;
    20     }
    21 
    22     @Autowired
    23     private ApplicationContext applicationContext;
    24 
    25     @Autowired
    26     public MyService (List<IndexInterface> indexList) {
    27         this.indexList = indexList;
    28     }
    29 }

            首先在AutowiredAnnotationBeanPostProcessor#postProcessProperties的方法中打上一个断点,然后右键断点加上条件过滤 beanName.equals("myService"),debug运行main方法,会在断点处停住,此时我们的调用栈是下图这样的:

            相信对Spring源码有过了解的园友对调用栈中的方法都不陌生,从下往上看,先经过了refresh方法,在finishBeanFactoryInitialization方法中getBean,然后走getObject的时候触发bean的初始化。

    bean的初始化是一个很复杂地方,在AbstractAutowireCapableBeanFactory#doCreateBean方法中,先创建一个BeanWrapper,它的内部成员变量wrappedObject中存放的就是实例化的MyService对象,只是此时未完成初始化,所以属性都是null(如下图所示)。再往后进入populateBean方法进行属性注入,这才逐渐逼近我们的目的地。

             不过在进入populateBean之前,需要先去看一下前置方法,即BeanWrapper创建的方法createBeanInstance。Spring在这个方法中先推断出合适的构造方法,然后实例化bean。在推断构造方法的时候(AbstractAutowireCapableBeanFactory#determineConstructorsFromBeanPostProcessors方法中调用了AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors方法进行的推断),有一个筛选标准就是会根据是否有@Autowired注解来选择用哪个构造器,具体详见AutowiredAnnotationBeanPostProcessor#findAutowiredAnnotation方法,此方法如下所示,功能就是看看当前构造器上加没加注解。

     1     @Nullable
     2     private AnnotationAttributes findAutowiredAnnotation(AccessibleObject ao) {
     3         if (ao.getAnnotations().length > 0) {  // autowiring annotations have to be local
     4             for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {// 此集合中只有两个值,一个是Autowired注解,一个是Value注解
     5                 AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ao, type);
     6                 if (attributes != null) {
     7                     return attributes;
     8                 }
     9             }
    10         }
    11         return null;
    12     }

    此处构造器的推断和属性注入,就是使用场景三【三、构造方法注入参数】中,@Autowired注解加在构造器上发挥的作用。

    走完createBeanInstance方法得到的BeanWrapper中,可以看到属性wrappedObject中已经对indexList进行了依赖注入

    进行到这里,有必要重新梳理清楚类构造器注入时的调用关系,示例的调用栈图如下所示:

    1、在myService对象进行实例化调用构造器时,执行AbstractAutowireCapableBeanFactory#autowireConstructor方法;

    2、进入到另一个类ConstructorResolver的autowireConstructor方法中;

    2.1、调用同类下的resolveAutowiredArgument方法,该方法会调用DefaultListableBeanFactory下的resolveDependency方法,此方法会调用到findAutowireCandidates方法,在该方法中有如下代码

    1 for (String candidate : candidateNames) {
    2             if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
    3                 addCandidateEntry(result, candidate, descriptor, requiredType);
    4             }
    5         }

    其中的candidateNames就是构造器中要注入的对象名字indexService和otherIndexService,此处通过循环调用addCandidateEntry来获取这两个name对应的bean;

    2.2、在DefaultListableBeanFactory的addCandidateEntry方法中,调到了DependencyDescriptor#resolveCandidate方法,在此方法中调用的getBean方法获取它的成员变量bean。

    DependencyDescriptor#resolveCandidate方法如下所示:

    1     public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
    2             throws BeansException {
    3 
    4         return beanFactory.getBean(beanName);
    5     }

     然后又进入了下一次的getBean逻辑。此处就是这样完成的构造器方法参数注入。

        下面进入populateBean中。看源码经过一个for循环和一个NAME或者TYPE模式的判断之后,进入了BeanPostProcessor的循环调用中,通过遍历后置处理器,调用了AutowiredAnnotationBeanPostProcessor#postProcessProperties,也就是一开始我们打断点的地方,该方法源码如下:

     1 @Override
     2     public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
     3         InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
     4         try {
     5             metadata.inject(bean, beanName, pvs);
     6         }
     7         catch (BeanCreationException ex) {
     8             throw ex;
     9         }
    10         catch (Throwable ex) {
    11             throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
    12         }
    13         return pvs;
    14     }

    在第13行打断点,发现到13行的时候,bean中的属性已经被注入了,所以可以知道,是在第5行进行的属性注入。

    继续跟踪第5行,进入InjectionMetadata#inject方法:

     1 public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
     2         Collection<InjectedElement> checkedElements = this.checkedElements;
     3         Collection<InjectedElement> elementsToIterate =
     4                 (checkedElements != null ? checkedElements : this.injectedElements);
     5         if (!elementsToIterate.isEmpty()) {
     6             for (InjectedElement element : elementsToIterate) {
     7                 if (logger.isTraceEnabled()) {
     8                     logger.trace("Processing injected element of bean '" + beanName + "': " + element);
     9                 }
    10                 element.inject(target, beanName, pvs);
    11             }
    12         }
    13     }

     发现是从当前metadata对象中取的element对象,而通过断点可以看到,checkedElements中的Member对象就是当前bean中加了@Autowired注解的成员变量或者普通方法在反射包中对应的对象,随后通过element的inject方法进行的注入。那么问题来了,element对象是如何创建来的?inject方法又是如何将bean注入到成员变量中的?

     对于element对象的创建,还要返回postProcessProperties方法中查看上面的findAutowiringMetadata方法:

     1 private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
     2         // Fall back to class name as cache key, for backwards compatibility with custom callers.
     3         String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
     4         // Quick check on the concurrent map first, with minimal locking.
     5         InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
     6         if (InjectionMetadata.needsRefresh(metadata, clazz)) {
     7             synchronized (this.injectionMetadataCache) {
     8                 metadata = this.injectionMetadataCache.get(cacheKey);
     9                 if (InjectionMetadata.needsRefresh(metadata, clazz)) {
    10                     if (metadata != null) {
    11                         metadata.clear(pvs);
    12                     }
    13                     metadata = buildAutowiringMetadata(clazz);
    14                     this.injectionMetadataCache.put(cacheKey, metadata);
    15                 }
    16             }
    17         }
    18         return metadata;
    19     }

     通过断点到这个方法中,发现此时injectionMetadataCache中已经有了myService对应的InjectionMetadata,此方法只是从map中取出返回。没办法了,还要继续追寻下去,AutowiredAnnotationBeanPostProcessor中的injectionMetadataCache属性是什么时候触发的初始化?

    在当前类中查询injectionMetadataCache的put方法,发现只有这一个地方,所以继续在这里断点一下,看看什么时候触发的injectionMetadataCache.put。

     

     发现原来就是在doCreateBean的applyMergedBeanDefinitionPostProcessors方法中触发的put操作。

    下面继续追寻inject方法中Spring如何完成的属性注入。

    属性注入进入内部类 AutowiredFieldElement的方法inject中,方法注入进入的是AutowiredMethodElement中。在inject方法中可以看到我们的老朋友DefaultListableBeanFactory#resolveDependency方法,即通过这个方法获取到对应的bean对象,最后通过反射完成的赋值或方法调用。

    这里我们第二次遇到DefaultListableBeanFactory#resolveDependency,发现它是@Autowired注解注入构造器参数、注入成员变量、注入方法参数必经的方法,所以必须继续搞明白它。

    追踪resolveDependency方法,进入DefaultListableBeanFactory#resolveMultipleBeans方法,该方法属于@Autowired注解的核心方法,虽然很长,但需要贴出源代码:

     1 @Nullable
     2     private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName,
     3             @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {
     4 
     5         final Class<?> type = descriptor.getDependencyType();
     6                 // 0、暂时不清楚是做什么用的...
     7         if (descriptor instanceof StreamDependencyDescriptor) {
     8             Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
     9             if (autowiredBeanNames != null) {
    10                 autowiredBeanNames.addAll(matchingBeans.keySet());
    11             }
    12             Stream<Object> stream = matchingBeans.keySet().stream()
    13                     .map(name -> descriptor.resolveCandidate(name, type, this))
    14                     .filter(bean -> !(bean instanceof NullBean));
    15             if (((StreamDependencyDescriptor) descriptor).isOrdered()) {
    16                 stream = stream.sorted(adaptOrderComparator(matchingBeans));
    17             }
    18             return stream;
    19         }
    20         else if (type.isArray()) { // 1、判断要注入的是不是一个数组,可见除了集合注入外,也可以以数组的形式注入bean
    21             Class<?> componentType = type.getComponentType();
    22             ResolvableType resolvableType = descriptor.getResolvableType();
    23             Class<?> resolvedArrayType = resolvableType.resolve(type);
    24             if (resolvedArrayType != type) {
    25                 componentType = resolvableType.getComponentType().resolve();
    26             }
    27             if (componentType == null) {
    28                 return null;
    29             }
    30             Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType,
    31                     new MultiElementDescriptor(descriptor));
    32             if (matchingBeans.isEmpty()) {
    33                 return null;
    34             }
    35             if (autowiredBeanNames != null) {
    36                 autowiredBeanNames.addAll(matchingBeans.keySet());
    37             }
    38             TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
    39             Object result = converter.convertIfNecessary(matchingBeans.values(), resolvedArrayType);
    40             if (result instanceof Object[]) {
    41                 Comparator<Object> comparator = adaptDependencyComparator(matchingBeans);
    42                 if (comparator != null) {
    43                     Arrays.sort((Object[]) result, comparator);
    44                 }
    45             }
    46             return result;
    47         }
    48         else if (Collection.class.isAssignableFrom(type) && type.isInterface()) { // 2、判断注入的是不是集合的接口类(List、Set等)
    49             Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();
    50             if (elementType == null) {
    51                 return null;
    52             }
    53             Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,
    54                     new MultiElementDescriptor(descriptor));
    55             if (matchingBeans.isEmpty()) {
    56                 return null;
    57             }
    58             if (autowiredBeanNames != null) {
    59                 autowiredBeanNames.addAll(matchingBeans.keySet());
    60             }
    61             TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
    62             Object result = converter.convertIfNecessary(matchingBeans.values(), type);
    63             if (result instanceof List) {
    64                 Comparator<Object> comparator = adaptDependencyComparator(matchingBeans);
    65                 if (comparator != null) {
    66                     ((List<?>) result).sort(comparator);
    67                 }
    68             }
    69             return result;
    70         }
    71         else if (Map.class == type) { ///3、判断要注入的是不是map类
    72             ResolvableType mapType = descriptor.getResolvableType().asMap();
    73             Class<?> keyType = mapType.resolveGeneric(0);
    74             if (String.class != keyType) {
    75                 return null;
    76             }
    77             Class<?> valueType = mapType.resolveGeneric(1);
    78             if (valueType == null) {
    79                 return null;
    80             }
    81             Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType,
    82                     new MultiElementDescriptor(descriptor));
    83             if (matchingBeans.isEmpty()) {
    84                 return null;
    85             }
    86             if (autowiredBeanNames != null) {
    87                 autowiredBeanNames.addAll(matchingBeans.keySet());
    88             }
    89             return matchingBeans;
    90         }
    91         else { // 4、其他情况返回空,进入doResolveDependency方法做默认处理
    92             return null;
    93         }
    94     }

    主要看1/2/3的注释,可以知道Spring支持多种注入方式就是在这里实现的。我们能发现,在获取bean的时候都是调用了findAntowireCandidates方法,而且第4中默认的情况,在外部的doResolveDenpency方法中也调用了findAutowireCandidates方法。

    至于findAutowireCandidates方法是如何完成的属性获取?是通过type还是name获取到的bean?我们下期继续!

  • 相关阅读:
    CEAA自动汇编脚本常用命令
    PIC之拉电流和灌电流
    CHARRANGE 结构
    汇编中的lodsb和stosb、lodsd和stosd指令
    汇编中的STOSB与STOSD指令
    汇编中的CLD指令
    SQL中distinct的用法
    SQL union介绍
    【项目排期】测试排期问题思考
    SQL join的介绍
  • 原文地址:https://www.cnblogs.com/zzq6032010/p/11605344.html
Copyright © 2020-2023  润新知