Spring注解装配:@Autowired和@Resource使用及原理详解-灵析社区

后端求offer版

1.背景

@Resource@Autowired都是实现bean的注入,在日常开发中使用非常频繁,但是使用体验不太一样,笔者喜欢用@Resource,因为在使用@Autowired时IDEA会出现一些警告爆红提示:

Field injection is not recommended (字段注入是不被推荐的)

Spring团队不推荐属性字段注入的方式(ps:日常开发中我们一般都是字段注入,简单了然呀),建议使用基于构造函数的依赖项注入。

还有报红如下:IDEA提示找不到该类型的bean,这并不是错误。。。项目启动时mapper bean会被注入到Spring上下文容器中

综上情况和个人有强迫症看到警告和爆红就认为代码写得有问题,所以我选择了@Resource。但是这里要申明一下@Autowied本身是没问题的,可以尽情使用,出现以上报红是IDEA工具的问题。

项目推荐:基于SpringBoot2.x、SpringCloud和SpringCloudAlibaba企业级系统架构底层框架封装,解决业务开发时常见的非功能性需求,防止重复造轮子,方便业务快速开发和企业技术栈框架统一管理。引入组件化的思想实现高内聚低耦合并且高度可配置化,做到可插拔。严格控制包依赖和统一版本管理,做到最少化依赖。注重代码规范和注释,非常适合个人学习和企业使用
Github地址:github.com/plasticene/…
Gitee地址:gitee.com/plasticene3…

2.概述

Spring 支持使用@Autowired, @Resource注解进行依赖注入

2.1 @Autowired和@Resource定义

@Autowired

@Autowired为Spring 框架提供的注解,需要导入包org.springframework.beans.factory.annotation.Autowired。源码如下

/**
 * @since 2.5
 * @see AutowiredAnnotationBeanPostProcessor
 * @see Qualifier
 * @see Value
 */
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
​
  /**
   * Declares whether the annotated dependency is required.
   * <p>Defaults to {@code true}.
   */
  boolean required() default true;
​
}

① 按照type在上下文中查找匹配的bean,查找type为Svc的bean

② 如果有多个bean,则按照name进行匹配

  • 如果有@Qualifier注解,则按照@Qualifier指定的name进行匹配,查找name为svcA的bean
  • 如果没有,则按照变量名进行匹配,查找name为svcA的bean

③ 匹配不到,则报错。(@Autowired(required=false),如果设置requiredfalse(默认为true),则注入失败时不会抛出异常

@Resource

@Resource 是JDK1.6支持的注解,由J2EE提供,需要导入包javax.annotation.Resource。源码如下:

@Target({TYPE, FIELD, METHOD})
@Retention(RUNTIME)
public @interface Resource {
  
    String name() default "";
    String lookup() default "";
    Class<?> type() default java.lang.Object.class;
    enum AuthenticationType {
            CONTAINER,
            APPLICATION
    }
    AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
    boolean shareable() default true;
    String mappedName() default "";
    String description() default "";
}

默认按照名称进行装配,名称可以通过name属性进行指定。也提供按照byType 注入。

@Resource有两个重要的属性:name 和 type,而Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型

如果没有指定name属性,当注解写在字段上时,默认取字段名,按照名称查找。

当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找依赖对象。

当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。

@Resource的作用相当于@Autowired,只不过@Autowired按照byType自动注入

2.2 @Autowired和@Resource区别

依赖识别方式:@Autowired默认是byType可以使用@Qualifier指定Name,@Resource默认ByName如果找不到则ByType

适用对象:@Autowired可以对构造器、方法、参数、字段使用,@Resource只能对方法、字段使用

提供方:@Autowired是Spring提供的,@Resource是JSR-250提供的

3.实现原理

3.1 @Autowired实现原理

Spring中通过AutowiredAnnotationBeanPostProcessor来解析注入注解为目标注入值。该class继承InstantiationAwareBeanPostProcessorAdapter,实现了MergedBeanDefinitionPostProcessor,PriorityOrdered, BeanFactoryAware等接口,重写的方法将在IOC创建bean的时候被调用。

public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
    implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware{
    /**
     * Create a new {@code AutowiredAnnotationBeanPostProcessor} for Spring's
     * standard {@link Autowired @Autowired} and {@link Value @Value} annotations.
     * <p>Also supports JSR-330's {@link javax.inject.Inject @Inject} annotation,
     * if available.
     */
    @SuppressWarnings("unchecked")
    public AutowiredAnnotationBeanPostProcessor() {
      this.autowiredAnnotationTypes.add(Autowired.class);
      this.autowiredAnnotationTypes.add(Value.class);
      try {
        this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
            ClassUtils.forName("javax.inject.Inject",        AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
        logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
      }
      catch (ClassNotFoundException ex) {
        // JSR-330 API not available - simply skip.
      }
    }
  
  ......
  
}

前面已经提到了是Spring创建bean的时候调用,即当使用DefaultListableBeanFactory来获取想要的bean的时候会调用AutowiredAnnotationBeanPostProcessor,经过调用AbstractBeanFactory中的getBean方法,继续追踪源码最后在AbstractAutowireCapableBeanFactory类中的createBean方法中找到了调用解析@autowired的方法:doCreateBean()

  protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
​
    ......
​
    // Allow post-processors to modify the merged bean definition.
    // 判断是否有后置处理
    // 如果有后置处理,则允许后置处理修改 BeanDefinition
    synchronized (mbd.postProcessingLock) {
      if (!mbd.postProcessed) {
        try {
          // 重点  重点  重点
          // 这里会调用AutowiredAnnotationBeanPostProcessor查找解析注入的元信息
          applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); 
        }
        catch (Throwable ex) {
          throw new BeanCreationException(mbd.getResourceDescription(), beanName,
              "Post-processing of merged bean definition failed", ex);
        }
        mbd.postProcessed = true;
      }
    }
​
    ......
​
    // Initialize the bean instance.
    // 开始初始化 bean 实例对象
    Object exposedObject = bean;
    try {
      // 对 bean 进行填充,将各个属性值注入,其中,可能存在依赖于其他 bean 的属性
      // 则会递归初始依赖 bean
      populateBean(beanName, mbd, instanceWrapper);
      // 调用初始化方法
      exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
    catch (Throwable ex) {
      if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
        throw (BeanCreationException) ex;
      }
      else {
        throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
      }
    }
​
    .......
      
    return exposedObject;
  }

执行到applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName)时会调用AutowiredAnnotationBeanPostProcessorpostProcessMergedBeanDefinition()完成注入元信息的查找解析。

进入populateBean()方法:会调用AutowiredAnnotationBeanPostProcessor方法postProcessPropertyValues()方法完成属性值注入,因为AutowiredAnnotationBeanPostProcessor是继承了InstantiationAwareBeanPostProcessorAdapter,是一个后置处理器。

接下来基于这两个核心入口分别讲述一下:

查找解析元信息

实现了接口类MergedBeanDefinitionPostProcessor的方法postProcessMergedBeanDefinition,这个方法是合并我们定义类的信息,比如:一个类继承了其它类,这个方法会把父类属性和信息合并到子类中

@Override
  public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
    // 根据bean的名称、类型查找注入的元信息
    InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
    metadata.checkConfigMembers(beanDefinition);
  

findAutowiringMetadata()代码如下:

 private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
    // Fall back to class name as cache key, for backwards compatibility with custom callers.
    //先读缓存
    String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
    // Quick check on the concurrent map first, with minimal locking.
    InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
    if (InjectionMetadata.needsRefresh(metadata, clazz)) {
      synchronized (this.injectionMetadataCache) {
        metadata = this.injectionMetadataCache.get(cacheKey);
        if (InjectionMetadata.needsRefresh(metadata, clazz)) {
          if (metadata != null) {
            metadata.clear(pvs);
          }
          //把查找出来的元信息进行构建
          metadata = buildAutowiringMetadata(clazz);
          this.injectionMetadataCache.put(cacheKey, metadata);
        }
      }
    }
    return metadata;
  }
​

构建注解元信息 buildAutowiringMetadata()

​
 
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
    //判断是否符合条件注解类型(@AutoWired和@Value)
    if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
      return InjectionMetadata.EMPTY;
    }
 
    List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
    Class<?> targetClass = clazz;
 
    do {
      final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
      //先处理注解字段
      ReflectionUtils.doWithLocalFields(targetClass, field -> {
        //是不是要找的字段
        MergedAnnotation<?> ann = findAutowiredAnnotation(field);
        if (ann != null) {
          //静态字段不支持@Autowired
          if (Modifier.isStatic(field.getModifiers())) {
            if (logger.isInfoEnabled()) {
              logger.info("Autowired annotation is not supported on static fields: " + field);
            }
            return;
          }
          boolean required = determineRequiredStatus(ann);
          currElements.add(new AutowiredFieldElement(field, required));
        }
      });
 
      //再处理注解方法
      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))) {
          //@Autowired不支持静态方法
          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);
          currElements.add(new AutowiredMethodElement(method, required, pd));
        }
      });
 
      elements.addAll(0, currElements);
      targetClass = targetClass.getSuperclass();
    }
    while (targetClass != null && targetClass != Object.class);
 
    return InjectionMetadata.forElements(elements, clazz);
  }
​

基于上面方法找到了所有需要注入的元信息并进行解析,这个过程也是一个依赖查找过程。

属性值注入

属性注入的通过AutowiredAnnotationBeanPostProcessor方法postProcessPropertyValues()方法完成的

​
​
  @Override
  public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
        //元信息查找、解析,在上一步已经分析过了
    InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
    try {
            //进行注入
      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;
  }
 
 
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);
        }
        //注入
        element.inject(target, beanName, pvs);
      }
    }
  }
 
       /**
     * Either this or {@link #getResourceToInject} needs to be overridden.
     */
    protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
        throws Throwable {
      //字段注入
      if (this.isField) {
        Field field = (Field) this.member;
        //设置字段权限为可以访问权限
        ReflectionUtils.makeAccessible(field);
        field.set(target, getResourceToInject(target, requestingBeanName));
      }
      else {
        //方法注入    
        if (checkPropertySkipping(pvs)) {
          return;
        }
        try {
          Method method = (Method) this.member;
          //设置方法权限为可以访问权限
          ReflectionUtils.makeAccessible(method);
          method.invoke(target, getResourceToInject(target, requestingBeanName));
        }
        catch (InvocationTargetException ex) {
          throw ex.getTargetException();
        }
      }
    }

自此基于@Autowired依赖注入核心逻辑就实现了。

3.2 @Resource实现原理

@Resource@Autowired的实现逻辑和流程基本是一样的,只是@Resource是通过CommonAnnotationBeanPostProcessor实现的,这里由于具体逻辑和实现细节和上面的@Autowired差不多,这里就不再赘述。


阅读量:2015

点赞量:0

收藏量:0