终于有人把@Autowired 和 @Resource 的区别说清楚了!

@Autowired 和 @Resource 都是 Spring/Spring Boot 项目中,用来进行依赖注入的注解。它们都提供了将依赖对象注入到当前对象的功能,但二者却有众多不同,并且这也是常见的面试题之一,所以我们今天就来盘它。
@Autowired 和 @Resource 的区别主要体现在以下 5 点:

  • 1.来源不同;
  • 2.依赖查找的顺序不同;
  • 3.支持的参数不同;
  • 4.依赖注入的用法不同;
  • 5.编译器 IDEA 的提示不同。

1.来源不同

@Autowired 和 @Resource 来自不同的“父类”,其中 @Autowired 是 Spring 定义的注解,而 @Resource 是 Java 定义的注解,它来自于 JSR-250(Java 250 规范提案)

小知识:JSR 是 Java Specification Requests 的缩写,意思是“Java 规范提案”。任何人都可以提交 JSR 给 Java 官方,但只有最终确定的 JSR,才会以 JSR-XXX 的格式发布,如 JSR-250,而被发布的 JSR 就可以看作是 Java 语言的规范或标准。

2.依赖查找顺序不同

依赖注入的功能,是通过先在 Spring IoC 容器中查找对象,再将对象注入引入到当前类中。而查找有分为两种实现:按名称(byName)查找或按类型(byType)查找,其中 @Autowired 和 @Resource 都是既使用了名称查找又使用了类型查找,但二者进行查找的顺序却截然相反。

2.1 @Autowired 查找顺序

@Autowired 是先根据类型(byType)查找,如果存在多个 Bean 再根据名称(byName)进行查找,它的具体查找流程如下:
在这里插入图片描述

关于以上流程,可以通过查看 Spring 源码中的 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues 实现分析得出,源码执行流程如下图所示:
在这里插入图片描述

2.2 @Resource 查找顺序

@Resource 是先根据名称查找,如果(根据名称)查找不到,再根据类型进行查找,它的具体流程如下图所示:
在这里插入图片描述

关于以上流程可以在 Spring 源码的 org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#postProcessPropertyValues 中分析得出。虽然 @Resource 是 JSR-250 定义的,但是由 Spring 提供了具体实现,它的源码实现如下:
在这里插入图片描述

2.3 查找顺序小结

由上面的分析可以得出:

  • @Autowired 先根据类型(byType)查找,如果存在多个(Bean)再根据名称(byName)进行查找;
  • @Resource 先根据名称(byName)查找,如果(根据名称)查找不到,再根据类型(byType)进行查找。

3.支持的参数不同

@Autowired 和 @Resource 在使用时都可以设置参数,比如给 @Resource 注解设置 name 和 type 参数,实现代码如下:


@Resource(name = "userinfo", type = UserInfo.class)
private UserInfo user;

   
  • 1
  • 2
  • 3

但二者支持的参数以及参数的个数完全不同,其中 @Autowired 只支持设置一个 required 的参数,而 @Resource 支持 7 个参数,支持的参数如下图所示:
image.png
image.png
在这里插入图片描述

4.依赖注入的支持不同

@Autowired 和 @Resource 支持依赖注入的用法不同,常见依赖注入有以下 3 种实现:

  • 属性注入
  • 构造方法注入
  • Setter 注入
    这 3 种实现注入的实现代码如下。

a) 属性注入

@RestController
public class UserController {
    // 属性注入
    @Autowired
    private UserService userService;
<span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span><span class="token string">"/add"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token class-name">UserInfo</span> <span class="token function">add</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">,</span> <span class="token class-name">String</span> password<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
    <span class="token keyword">return</span> userService<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>username<span class="token punctuation">,</span> password<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

b) 构造方法注入


@RestController
public class UserController {
    // 构造方法注入
    private UserService userService;
<span class="token annotation punctuation">@Autowired</span>
<span class="token keyword">public</span> <span class="token class-name">UserController</span><span class="token punctuation">(</span><span class="token class-name">UserService</span> userService<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>userService <span class="token operator">=</span> userService<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span><span class="token string">"/add"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token class-name">UserInfo</span> <span class="token function">add</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">,</span> <span class="token class-name">String</span> password<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
    <span class="token keyword">return</span> userService<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>username<span class="token punctuation">,</span> password<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

c) Setter 注入

@RestController
public class UserController {
    // Setter 注入
    private UserService userService;
<span class="token annotation punctuation">@Autowired</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setUserService</span><span class="token punctuation">(</span><span class="token class-name">UserService</span> userService<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>userService <span class="token operator">=</span> userService<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span><span class="token string">"/add"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token class-name">UserInfo</span> <span class="token function">add</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">,</span> <span class="token class-name">String</span> password<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
    <span class="token keyword">return</span> userService<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>username<span class="token punctuation">,</span> password<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

其中, @Autowired 支持属性注入、构造方法注入和 Setter 注入,而 @Resource 只支持属性注入和 Setter 注入,当使用 @Resource 实现构造方法注入时就会提示以下错误:
在这里插入图片描述

5.编译器提示不同

当使用 IDEA 专业版在编写依赖注入的代码时,如果注入的是 Mapper 对象,那么使用 @Autowired 编译器会提示报错信息,报错内容如下图所示:
在这里插入图片描述

虽然 IDEA 会出现报错信息,但程序是可以正常执行的。
然后,我们再将依赖注入的注解更改为 @Resource 就不会出现报错信息了,具体实现如下:
在这里插入图片描述

总结

@Autowired 和 @Resource 都是用来实现依赖注入的注解(在 Spring/Spring Boot 项目中),但二者却有着 5 点不同:

  • 来源不同:@Autowired 来自 Spring 框架,而 @Resource 来自于(Java)JSR-250;
  • 依赖查找的顺序不同:@Autowired 先根据类型再根据名称查询,而 @Resource 先根据名称再根据类型查询;
  • 支持的参数不同:@Autowired 只支持设置 1 个参数,而 @Resource 支持设置 7 个参数;
  • 依赖注入的用法支持不同:@Autowired 既支持构造方法注入,又支持属性注入和 Setter 注入,而 @Resource 只支持属性注入和 Setter 注入;
  • 编译器 IDEA 的提示不同:当注入 Mapper 对象时,使用 @Autowired 注解编译器会提示错误,而使用 @Resource 注解则不会提示错误.。
    如有侵权,请联系删除
    参考文献:https://developer.aliyun.com/article/1003903?spm=a2c6h.24874632.expert-profile.170.706570abMFaSAj
<think>好的,我现在要准备一个关于Spring框架中Bean注入方式的面试问题。用户希望得到结构清晰、逐步解释的回答,同时需要符合系统级指令,比如正确使用LaTeX格式,并且用中文回答。首先,我需要回忆一下Spring中Bean注入的几种主要方式,并确保自己对这些概念的理解准确。 首先,Bean注入通常分为两大类:构造器注入Setter注入。这是最常见的两种方式,我记得构造器注入是通过类的构造函数来注入依赖,而Setter注入则是通过setter方法。然后还有字段注入,虽然不推荐,但在一些旧代码中可能还会看到。除此之外,可能还有接口注入,不过Spring并不直接支持这种方式,但有时候会被提到。另外,可能还有其他方式,比如方法注入或者使用@Autowired注解的不同应用场景。 接下来,我需要详细展开每一种注入方式。例如,构造器注入需要明如何在配置文件中配置构造函数参数,或者在Java配置类中使用@Bean注解。同时,要提到Spring 4.3之后的改进,比如如果类只有一个构造器,可以省略@Autowired注解。此外,构造器注入的优点,比如不可变性确保依赖不为空。 Setter注入的话,要明如何通过property标签或者在setter方法上使用@Autowired。可能还需要比较构造器注入Setter注入的适用场景,比如可选依赖更适合Setter注入,而必需依赖用构造器注入更好。 字段注入的话,虽然简单,直接使用@Autowired在字段上,但存在一些问题,比如无法注入不可变字段,测试困难,隐藏依赖关系等,所以不推荐使用。 另外,可能还需要提到其他方式,比如使用@Resource或者@Inject注解,这些是Java标准注解,@Autowired区别是什么。例如,@Resource默认按名称装配,而@Autowired按类型装配。 还有,方法注入,比如在配置类中使用@Bean注解的方法,Spring会调用这些方法来创建Bean实例,并将返回值注册为Bean。这种情况下,方法参数会自动注入依赖。 此外,可能还需要提到在XML配置中的注入方式,比如使用constructor-argproperty元素,但现在的趋势是使用注解Java配置。 在组织这些内容时,需要确保结构清晰,分点明,每个方式给出定义、示例、优缺点以及适用场景。同时,要注意使用正确的LaTeX格式,比如行内公式用$...$,独立公式用$$...$$,但这里可能用到的技术术语可能不需要数学公式,但如果有涉及到表达式的地方要符合格式要求。例如,如果提到某个模式或表达式,可能需要用LaTeX,但Bean注入可能不需要,不过要注意用户提到的变量或代码可能需要适当处理。 还要确保回答真实可靠,可能需要查阅Spring官方文档确认某些细节,比如构造器注入在Spring版本中的变化,或者@Autowired的使用条件。例如,确认在Spring 4.3之后,单一构造器的类是否需要显式@Autowired。 另外,用户要求使用中文,所以需要注意术语的准确翻译,比如“构造器注入”对应“Constructor Injection”,“Setter注入”对应“Setter Injection”,“字段注入”是“Field Injection”等。 可能还需要注意面试中常问的问题,比如推荐哪种注入方式,为什么构造器注入更被推荐,比如因为不可变性、更好的测试支持、避免循环依赖问题等。同时,可能提到Spring团队推荐构造器注入用于强制依赖,Setter注入用于可选依赖。 总结下来,回答的结构应该分为几个主要部分,每个注入方式单独一点,解释清楚定义、实现方式、示例、优缺点,最后可能有总结对比,或者面试中的常见问题点。 现在需要检查是否有遗漏的注入方式,比如方法注入或者Lookup方法注入,这些可能在某些特定场景下使用,但可能不是面试中的重点,但简要提及可以显示知识的全面性。 另外,是否需要提到基于Java的配置基于注解的配置,例如@Configuration@Bean,或者组件扫描@Component等注解,这些可能属于Bean的定义注册方式,而注入方式更多是指依赖注入的方式,但可能需要区分清楚。 确保回答中没有错误,比如构造器注入是否支持可选依赖,实际上构造器注入的参数是必须的,而Setter注入的参数是可选的,因为可以不用调用setter方法。这可能需要在优缺点中提到。 最后,要确保使用正确的LaTeX格式,虽然问题中没有明显的数学公式,但如果有代码示例,可能需要用反引号或者代码块,但根据用户指令,所有行内数学表达式必须用$...$,但代码部分可能不需要,但需要确认用户是否将代码视为需要格式化的部分。不过用户给的例子都是数学表达式,所以可能代码部分不需要LaTeX,但需要正确使用代码标记。然而在系统级指令中,用户要求的是所有行内数学表达式使用$...$,所以可能代码示例需要用其他方式处理,比如用代码块或者中文描述,避免使用LaTeX来写代码。 现在组织语言,确保每个点清晰,逐步解释,帮助用户理解不同注入方式的区别应用场景,同时符合面试准备的深度广度。</think>在Spring框架中,Bean注入是依赖注入(DI)的核心实现方式。以下是常见的Bean注入方式及其特点,适用于面试回答: --- ### **1. 构造器注入(Constructor Injection)** **定义**:通过类的构造函数注入依赖。 **实现方式**: - **XML配置**:`<constructor-arg>` 标签。 - **注解**:在构造方法上使用 `@Autowired`(Spring 4.3+ 单构造器可省略)。 - **Java配置类**:直接在 `@Bean` 方法中传递参数。 **示例**: ```java public class ServiceA { private final ServiceB serviceB; // 构造器注入 public ServiceA(ServiceB serviceB) { this.serviceB = serviceB; } } ``` **优点**: - 依赖不可变(`final` 字段),线程安全。 - 强制依赖初始化,避免 `NullPointerException`。 - 推荐用于**强依赖**场景。 --- ### **2. Setter注入(Setter Injection)** **定义**:通过Setter方法注入依赖。 **实现方式**: - **XML配置**:`<property>` 标签。 - **注解**:在Setter方法上使用 `@Autowired`。 **示例**: ```java public class ServiceA { private ServiceB serviceB; // Setter注入 @Autowired public void setServiceB(ServiceB serviceB) { this.serviceB = serviceB; } } ``` **优点**: - 灵活性高,适合**可选依赖**。 - 支持循环依赖(需配合 `@Lazy`)。 **缺点**: - 依赖可变,可能引发状态不一致。 --- ### **3. 字段注入(Field Injection)** **定义**:直接在字段上使用 `@Autowired` 注入依赖。 **实现方式**:字段标注 `@Autowired`。 **示例**: ```java public class ServiceA { @Autowired private ServiceB serviceB; } ``` **缺点**: - 违反封装原则,依赖关系隐藏。 - 无法注入 `final` 字段。 - 测试困难(需通过反射或Spring容器)。 - **不推荐生产代码使用**。 --- ### **4. 接口注入(Interface Injection)** **定义**:通过实现特定接口完成注入(Spring不原生支持,需自定义)。 **示例**: ```java public interface InjectServiceB { void inject(ServiceB serviceB); } public class ServiceA implements InjectServiceB { private ServiceB serviceB; @Override public void inject(ServiceB serviceB) { this.serviceB = serviceB; } } ``` **适用场景**:需动态切换实现类时(较少使用)。 --- ### **5. 方法注入(Method Injection)** **定义**:通过任意方法注入依赖(参数自动装配)。 **实现方式**:在方法上使用 `@Autowired`。 **示例**: ```java public class ServiceA { private ServiceB serviceB; @Autowired public void init(ServiceB serviceB) { this.serviceB = serviceB; } } ``` --- ### **6. 其他注解** - **`@Resource`**:按名称注入(默认 `byName`),属于JSR-250标准。 - **`@Inject`**:按类型注入(类似 `@Autowired`),属于JSR-330标准。 --- ### **面试常见问题** 1. **构造器注入 vs. Setter注入**: - 构造器注入:强制依赖、不可变、推荐首选。 - Setter注入:可选依赖、灵活性高。 2. **为什么字段注入不推荐**? - 破坏封装性、测试困难、依赖不透明。 3. **如何解决循环依赖**? - 使用Setter注入 + `@Lazy` 延迟加载。 --- ### **总结** - **强依赖**:优先构造器注入。 - **可选依赖**:使用Setter注入。 - **避免字段注入**,遵循面向对象设计原则。 此回答覆盖了常见面试考点,结合代码示例优缺点对比,帮助面试官理解候选人对Spring DI的掌握深度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值