注解@Autowired和@Resource的区别总结

零、前言

@Autowired@Resource注解都可以在Spring应用中进行声明式的依赖注入。以前都是看的网上关于两者的区别,但是实际和网上说的有出入,故从源码角度进行分析、验证。

以下源码基于spring 5.3.20(通过springboot 2.7.0引入)

一、结论

1、@Autowired注解总结

  • 可用于构造函数,成员变量以及set方法
  • Spring 4.3开始,如果目标Bean只有一个构造函数,则在该构造函数上可以省略@Autowired注解;如果目标Bean有多个构造函数则不可省略

@Autowired注入方式:

  • 按照type查找bean,如果使用@Qualifier注解声明了name,则从结果集中取出与该name相匹配的bean返回(此时可以视为通过name和type获取bean,但实质是先通过type获取所有bean,然后通过name筛选,详情见后文findAutowireCandidates()方法源码分析)
  • 如果没有使用@Qualifier注解,且找到多个bean,则判断这些bean中是否有使用@Primary注解和@Priority注解,有就返回优先级最高的哪一个bean,没有就按照字段名称去匹配bean,匹配成功返回,不成功抛出异常。(详情见后文determineAutowireCandidate()方法源码解析)

整体注入流程如下所示:

2、@Resource注解总结

  • 可用于成员变量以及set方法
  • 若不指定name属性,则会把name属性值处理为字段名set方法标识的字段名称
  • 若指定type属性,则type属性值必须与字段类型或set方法返回值类型为父子关系(type属性值可以是子类,也可以是超类),否则会抛出异常
  • @Resource先按照name属性值注入,若未找到,则按type属性值注入。即默认的name或指定的name找不到 bean ,就会按 type 注入

整体注入流程如下所示:

二、@Autowired注入过程源码分析

1、AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata():切入点

首先定位到org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata()方法,代码如下。可以看到,如果是在属性上声明@Autowired,则构造AutowiredFieldElement对象,如果是在方法上声明@Autowired,则构造AutowiredMethodElement对象。

 private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
     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) {
                 if (Modifier.isStatic(field.getModifiers())) {
                     if (logger.isInfoEnabled()) {
                         logger.info("Autowired annotation is not supported on static fields: " + field);
                     }
                     return;
                 }
                 boolean required = determineRequiredStatus(ann);
                 // 构造AutowiredFieldElement对象
                 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))) {
                 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);
                 // 构造AutowiredMethodElement对象
                 currElements.add(new AutowiredMethodElement(method, required, pd));
             }
         });
 ​
         elements.addAll(0, currElements);
         targetClass = targetClass.getSuperclass();
     }
     while (targetClass != null && targetClass != Object.class);
 ​
     return
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值