Spring IoC DI:控制反转与依赖注入

news2025/4/21 10:15:04

目录

前言 - Spring MVC 与 Spring IoC 之间的关系

1. IoC

1.1 Spring Framework, Spring MVC, Spring boot 之间的联系[面试题]

1.2 什么是容器

1.3 什么是 IoC 

2. DI

2.1 什么是 DI

 3. Spring IoC & DI

3.1 @Component

3.2 @Autowired

4. IoC 详解

4.1 ApplicationContext

4.1.1 getBean

4.1.2 Bean name

4.1.3 ApplicationContext vs BeanFactory [面试题]

4.2 类注解存储 Bean (五大类注解)

4.2.3 五大注解之间的区别和联系

4.2.3.1 层级区别

4.2.3.2 派生关系 

4.3 方法注解存储 Bean (@Bean)

 4.3.1 将 Bean 赋值给 @Bean 方法的形参

4.4 手动指定 Bean name

4.4.1 给五大注解指定 Bean name 

4.4.2 给 @Bean 指定 Bean name

4.5 修改默认扫描路径

5. DI 详解

5.1 属性注入

5.2 构造方法注入

5.2.1 修改默认构造方法

5.2.2 总结

5.3 setter 方法注入

5.4 三种注入方式的优缺点

5.4.1 属性注入

5.4.2 构造方法注入

5.4.3 setter 方法注入

5.5 @Autowired 存在的问题

5.5.1 @Primary [不常用]

5.5.2 @Qualifier [常用]

5.5.3 @Resource [常用]

5.6 @Autowired 和 @Resource 的区别 [高频面试题]

5.7 @Autowired 装配顺序


前言 - Spring MVC 与 Spring IoC 之间的关系

Spring MVC 更偏向前后端交互(数据接收和返回), Spring IoC 更偏向后端内部的工作.

特性Spring MVCSpring IoC
重点前后端交互 (数据接收和返回)后端内部组件的管理和依赖关系
关注点Web 应用程序的结构、请求处理、视图渲染Bean 的创建、配置、生命周期管理、依赖注入
典型注解@Controller、@RequestMapping、@GetMapping 等@Component、@Service、@Autowired、@Qualifier 等
适用场景构建 Web 应用程序管理应用程序内部的组件和依赖关系

Spring MVC 和 Spring IoC 并非相互独立的, 而是相互协作的.

1. IoC

1.1 Spring Framework, Spring MVC, Spring boot 之间的联系[面试题]

Spring Core (Spring Framework) 两大核心思想: IoC, AOP.

Spring Core 要比 Spring boot 早的多, Spring Core 大约是 04年 左右出来的, 而 Spring-boot 大约是 16年 起来的.

  • Spring Framework 类似于火车,高铁: 意味着 Spring Framework 是基础,是运行应用程序的基础设施。火车和高铁都是运输工具,而 Spring 提供了应用运行所需的核心功能,例如控制反转(IoC)、面向切面编程(AOP)等等。它就像一个底层的支撑系统,确保应用程序能正常运行。

  • Spring Boot 类似于 12306,功能不局限于火车: 12306 是中国的火车票订购网站。Spring Boot 简化了 Spring 应用程序的开发过程,就像 12306 简化了购买火车票的过程一样。你可以通过 12306 购买火车票,也可以查询其他信息,甚至预订酒店,它的功能不局限于火车票,同理 Spring boot 也是。 Spring Boot 不仅简化了 Spring 应用的搭建,还集成了很多常用的功能,使得开发者可以更专注于业务逻辑。

  • Spring MVC 类似于火车站,火车票代售点: 火车站和代售点是提供火车票服务的场所。Spring MVC 是 Spring Framework 的一个模块,专门处理 Web 请求。 它就像一个火车站或代售点,负责接收用户的请求,处理后返回响应。它处理用户与应用之间的交互。

总而言之,这个类比说明:

  • Spring Framework 是基础的运行环境

  • Spring Boot 简化了 Spring 应用的开发和配置

  • Spring MVC 负责处理 Web 请求和响应

1.2 什么是容器

Spring 中就包含了众多工具, IoC 容器就是其中之一.

在我们实际生活中, 容器是指可以装东西的物品, 杯子, 量筒, 碗, ...

在 java 中也是一样, 容器也是指用来装东西的.

我们之前其实已经接触过很多容器了:

  1. List, Map => 装载数据
  2. TomCat => 装载 Web 服务

Spring 也是一样, 只不过是用来装对象的.

1.3 什么是 IoC 

IoC 是指 控制反转(Inversion of Control), 是 Spring 的核心思想(但并不局限于 Spring). 

控制反转, 是指将控制权进行反转. 

这里举两个控制权反转的例子:

  1. 智能驾驶: 原来汽车的驾驶权在司机手上, 有了智能驾驶后, 驾驶权交给了智能驾驶系统来控制.
  2. 招聘, 员工的招聘,入职等控制权由老板转移到了 HR 的手中.

对象的控制权, 就是指能够控制对象的生成和销毁. 

而 Spring, 则是一个能够将对象的控制权进行反转的容器.

以我们之前学习的知识来讲, 对象的控制权应当在使用方的手中:

  • 若对象在一个方法中的创建, 那么这个对象的控制权就属于这个方法的. 如果这个方法被调用, 那么这个对象也就生成了; 如果这个方法调用完毕, 那么这个对象也就被 GC 回收了.

而 Spring 的 IoC, 则是将对象的控制权反转, 使得对象的控制权由 Spring 来控制(将对象存到 Spring 中, 后续若有需要, 就可以去取).

因此, IoC(控制反转) 可以认为是将对象存到 Spring 中.(注意: 存的是对象, 而不是类)

IoC, 能够有效降低资源使用双方的耦合度.

2. DI

2.1 什么是 DI

DI(Dependency Injection), 依赖注入.

容器在运行期间, 动态的为应用程序提供运行时所依赖的资源, 称之为依赖注入.
(程序运行时需要某个资源, 此时容器就为其提供这个资源)

简单来说, 就是我们的 java 进程中, 如果需要一个类的实例, 那我们可以不用手动去 new, 而是伸手向 Spring 要(Spring 的 IoC 已经把对象都存起来了, 此时取出来, 并完成赋值).

 3. Spring IoC & DI

IoC 是控制反转, DI 是依赖注入, 对于 Spring 这个容器来说, 也无非就是两件事:

  1. IoC => 把对象存到 Spring 中(存)
  2. DI => 把对象从 Spring 中取出来, 并给相关属性赋值(取)

存(IoC)和取(DI), 在 Spring 中也是使用两个注解来完成的:

  1. @Component => IoC => 存
  2. @Autowired => DI => 取

若想使用 @Autowired 从 Spring 中取对象, 那么首先要保证该对象已经存到了 Spring 中.
(必须先存后取, 不能没存就取)

因此, 必须对类使用 @Component 存放了对象后, 才能使用 @Autowired 来取对象.

3.1 @Component

@Component 是一个类注解, 对类使用, 表示向 Spring 容器中存该类的对象.(存)

@Component 是 @Controller 中的一个注解.

Bean 在 java 中有两个含义:

  1. JavaBean(SE 阶段) => 表示实体类
  2. Spring Bean => 表示由 Spring IoC 容器管理的对象

3.2 @Autowired

@Autowired 对属性使用, 即把对象从 Spring 中取出来, 并给属性赋值(取).

若要使用 @Autowired 从 Spring 中取对象, 前提是该对象被存到了 Spring 中(对应类使用了 @Component 注解).


4. IoC 详解

上文说到 @Component 能够将对象存储到 Spring 中.

其实, 不仅只有 @Component, 能够完成 IoC 的注解有两种.

1. 类注解:

  1. @Controller 控制层
  2. @Service 业务逻辑层
  3. @Repository 数据层
  4. @Component 组件层
  5. @Configuration 配置层

2. 方法注解

  1. @Bean

4.1 ApplicationContext

从 Spring 容器中获取 Bean 时, 有以下两种方式:

  1. 通过 @Autowired 隐示获取. (上文已讲)
  2. 通过 ApplicationContext 中的 getBean 方法显示获取.

如何理解 ApplicationContext 呢??

  1. Application: 应用
  2. Context: 上下文(可以理解为容器)

 ApplicationContext 就可以认为是一个容器, 其装载了 Spring 的运行环境.

而启动类的 run 方法, 返回的就是一个 ApplicationContext 对象:

 因此, 当我们使用相关注解将 Bean 放入 Spring 容器中后, 就可以通过 getBean 来获取 Bean, 并完成 DI.

4.1.1 getBean

通过 getBean 获取 Bean 时, 主要有三种方式:

  1. 通过 Bean name 获取 (Bean name 在 Spring 容器中必须是唯一的, 因此不同的 Bean name, 获取的一定是不同的 Bean)
  2. 通过 类对象 获取 (只有当该类型的对象在容器中只有一个时, 才能确保拿到的对象是正确的)
  3. 通过 Bean name 和类对象获取 (最精确)

4.1.2 Bean name

Bean name 可以手动指定. 当我们没有显式指定 Bean 的名称(Bean name)时, 那么 Bean name 具有默认值.

Bean name 默认名称的规则如下:

  1. Bean name 为类名的 小驼峰 形式. 例如, 类名: UserName; Bean 名称: userName

  2. 特殊情况: 当类名的第一个字母和第二个字母均为大写时, Bean name 就是类名. 例如: 类名: HCxxx; Bean 名称: HCxxx

注意:

Bean name 在 Spring 容器中必须是唯一的!! (类似身份证号)

如果存在多个具有相同名称的 Bean, Spring 会抛出异常!!

4.1.3 ApplicationContext vs BeanFactory [面试题]

 我们上文提到的 getBean 方法, 其实是 BeanFactory 接口中的方法:

而之所以 ApplicationContext 可以调用 getBean, 是因为 ApplicationContext 继承了 BeanFactory, 因此可以使用其父接口中的方法:

关于 ApplicationContext 和 BeanFactory 总结如下:

  1. ApplicationContext 和 BeanFactory 是 Spring 中的两个顶级接口.
  2. 继承关系和功能方面: BeanFactory 提供了基础的访问容器的能力(如 getBean), 而 ApplicationContext 是 BeanFactory 的子接口, 它除了继承 BeanFactory 的所有功能之外, 还添加了国际化支持, 资源访问支持, 以及事件传播等功能.
  3. 性能方面: ApplicationContext 一次性加载并初始化所有的 Bean 对象(饿汉模式); 而 BeanFactory 是需要哪个才去加载哪个, 更加轻量(懒汉模式).

4.2 类注解存储 Bean (五大类注解)

也就是通过以下 5 种注解将 Bean 存储到 Spring 容器中:

  1. @Controller 
  2. @Service 
  3. @Repository 
  4. @Component 
  5. @Configuration 

对类使用 @Controller 注解, 将该类的 Bean 存储到 Spring IoC 容器中, 接着使用 getBean 方法获取 Bean:

当然, 也可以使用 @Service, @Repository, @Configuration, @Component 将 Bean 存储到 IoC 中, 并且使用 getBean 来获取容器中的 Bean.

这 5 个注解的使用方法都是一模一样的, 这里不再一一列举了.

注意:

如果容器中只有一个该类型的 Bean, 那么无论通过哪种方式的 getBean 来获取 Bean, 获取到的都是同一个实例:

当我们使用 getBean 来获取 Bean 时, 一定要确保 Bean 已经存在于容器中, 否则会抛出异常:
(也就是说, 确保类已经使用了 @Controller 等注解)

此外, 我们使用 Bean name 来获取 Bean 时, Bean name 一定要书写正确, 否则就会在容器中查找不到该 Bean, 抛出异常: 

@SpringBootApplication
public class SpringIocDemoApplication {
    public static void main(String[] args) {
        // 获取包含 Spring 运行环境的容器
        ApplicationContext context = SpringApplication.run(SpringIocDemoApplication.class, args);

        // @Controller
        // 根据类型(类对象)获取 Bean
        HelloController bean = context.getBean(HelloController.class);
        // 根据 Bean name 获取 Bean
        HelloController bean1 = (HelloController) context.getBean("helloController");
        // 根据 类型 和 Bean name 共同获取 Bean
        HelloController bean2 = context.getBean("helloController", HelloController.class);
        System.out.println(bean);
        System.out.println(bean1);
        System.out.println(bean2);
        // @Service
        HelloService bean3 = context.getBean(HelloService.class);
        bean3.print();
        HelloService bean4 = (HelloService) context.getBean("helloService");
        bean4.print();
        HelloService bean5 = context.getBean("helloService", HelloService.class);
        bean5.print();

        // @Repository
        HelloRepository bean6 = context.getBean(HelloRepository.class);
        bean6.print();
        HelloRepository bean7 = (HelloRepository)context.getBean("helloRepository");
        bean7.print();
        HelloRepository bean8 = context.getBean("helloRepository", HelloRepository.class);
        bean8.print();

        // @Configuration
        HelloConfiguration bean9 = context.getBean(HelloConfiguration.class);
        bean9.print();
        HelloConfiguration bean10 = (HelloConfiguration)context.getBean("helloConfiguration");
        bean10.print();
        HelloConfiguration bean11 = context.getBean("helloConfiguration", HelloConfiguration.class);
        bean11.print();

        // @Component
        HelloComponent bean12 = context.getBean(HelloComponent.class);
        bean12.print();
        HelloComponent bean13 = (HelloComponent)context.getBean("helloComponent");
        bean13.print();
        HelloComponent bean14 = context.getBean("helloComponent", HelloComponent.class);
        bean14.print();}
}

4.2.3 五大注解之间的区别和联系

4.2.3.1 层级区别

上文说到, 五个注解都是类注解, 并且存储 Bean 时的用法也一模一样, 但是, 他们所用于的层次结构是不同的:

  1. @Controller 控制层
  2. @Service 业务逻辑层
  3. @Repository 数据层
  4. @Component 组件层
  5. @Configuration 配置层

这五个注解并没有明显的界限, 在实际工作中, 为了简化代码, 存在混用的情况.

但是, 在控制层中, 必须使用 @Controller, 不能使用其他注解替代:
(毕竟 @RestController = @Controller + @ResponseBody, 因此 @Controller 不能替换成其他注解)


(@RestController, @Controller 既作用于 IoC, 也作用域 MVC. 而 @RequestMapping 只作用于 MVC)

除了控制层的 @Controller 不能进行替换外, 其他注解是可以进行替换的, 但是不建议, 因为不同的注解含义不同, 在正确的层级使用对应的注解, 可以有效提高代码的可读性, 可维护性和可扩展性, 并降低项目的开发和维护成本.

4.2.3.2 派生关系 

此外, 通过观察五大注解的源码, 我们发现 @Controller, @Service, @Repository, @Configuration 均包含了 @Component. 

总结:

  1. @Component 注解: @Component 注解是 Spring IoC 框架中核心的注解. 告诉 Spring 容器, 这个类需要被 Spring 管理, 创建一个该类的 Bean 并存储到 IoC 容器中

  2. @Controller, @Service, @Repository, @Configuration: 这些注解都包含了 @Component, 是其派生注解. 并且在 @Component 的基础上提供了更明确的用途. 

Spring 扫描机制:

  • 当 Spring 项目启动时, 会进行组件扫描, 默认扫描是启动类所在路径及其子孙路径(之前博文有讲). 
  • Spring 会扫描所有带有 @Component 注解 (或其派生注解) 的类, 并将这些类实例化为 Bean, 然后注册到 IoC 容器中.

4.3 方法注解存储 Bean (@Bean)

@Bean 是一个方法注解, 会将该方法返回的 Bean 存储到 Spring 容器中. 

默认情况下, 该方法返回的 Bean, 其 Bean name 就是方法的名称.

此外, @Bean 必须搭配五大注解使用, 也就是说, 被 @Bean 注释的方法, 其所在的类必须有五大注解.
(因为只有加了五大注解的类, 才会被 Spring 扫描, 进而才能扫描到里面的方法)

注意: @Bean 方法不能是 private 或 final 的!!

当容器中只有一个类型的 Bean 只有一个时, 可以通过 getBean 类型方式(类对象方式)来获取:

但是, 当一个类型有多个 Bean 时, 以类型的方式获取 Bean, 就会抛出异常 :
(通过类型获取 Bean, 只适合容器中只有一个该类型的 Bean 的情况)

此时, 我们可以通过 Bean name 来获取指定的 Bean:
(此时 Bean name 为默认为方法名)

 4.3.1 将 Bean 赋值给 @Bean 方法的形参

当 @Bean 方法有形参传入时, Spring 会从容器中进行查找, 查找到对应类型的 Bean 后, 将该 Bean 赋值给 @Bean 方法的形参:

当要寻找的该类型的 Bean 在容器中存在多个时, 则会抛出异常:

上面这种情况是容器中的多个 Bean 的 Bean name 都和形参名称不同. 

也就是说, 有一种特殊情况: 即使容器中有多个该类型的 Bean, 但其中一个 Bean 的 Bean name 和参数名称相同时, 就会匹配到该 Bean, 并赋值给参数:

总结:

  1. @Bean 方法的参数名不一定需要与容器中存在的对应类型 Bean 的名称完全相同.
  2. Spring 容器首先根据参数的类型在容器中查找匹配的 Bean, 只有当存在多个相同类型的 Bean 时, 才会根据参数的名称来匹配对应的 Bean.

4.4 手动指定 Bean name

上文说到, Bean name 可以手动指定, 也可以使用默认值. 

不论是 IoC 中的类注解, 还是方法注解, 指定 Bean name 的方式都是一样的, 就是给对应注解的 value 属性赋值:

定义方式手动指定 Bean Name 的方法
@Component / @Service / @Repository / @Controller / @Configuration@Component("customName")
@Bean@Bean("customName") 

4.4.1 给五大注解指定 Bean name 

给五大注解中的 value 属性赋值, 就是指定 Bean name:

4.4.2 给 @Bean 指定 Bean name

给 @Bean 中的 value 属性赋值, 就是指定 Bean name.

与五大注解不同的是, @Bean 中的 value 属性是一个数组, 也就是说, 可以给一个 Bean 指定多个 Bean name:


4.5 修改默认扫描路径

在之前的博文中我们讲到, Spring 的默认扫描路径是: 启动类所在路径及其子孙路径.

但是, 我们也可以通过 @ComponentScan 手动指定 Spring 的扫描路径:
(修改后扫描路径不再是启动类所在路径, 而是手动指定的路径)


5. DI 详解

DI, 即依赖注入. 其中的 "依赖", 就是指 Spring 容器中存储的 Bean.

IoC 是将 Bean 放入到 Spring 容器中, 而依赖注入 (DI) 就是将 Bean 从容器中取出来并完成赋值.

如上图所示, @Autowired 就完成了依赖注入这个操作.

DI(依赖注入) 有三种方式:

  1. 属性注入
  2. 构造方法注入
  3. setter 方法注入

其实, 无论使用哪种形式的依赖注入 (构造方法注入、Setter 方法注入或属性注入), 本质都是将一个 Bean (依赖) 赋值给类中的 Bean 成员属性.

接下来, 我为大家逐个讲解.
(在完成注入前, 必须要完成 IoC, 即将 Bean 存储到 Spring 中, 下文的演示就不一一强调了)

5.1 属性注入

对类的属性进行 @Autowired 注解, 即进行属性注入:

其中, @Autowired 是根据类型在 Spring 容器中获取 Bean.

因此, 当同一类型的 Bean 在容器中存在多个时, 属性注入就会出现问题. 当然, 是有解决办法的, 下文会详讲.

注意: 使用属性注入时, 不能注入 final 修饰的属性:

5.2 构造方法注入

构造方法注入的最终目标是将 Bean 注入到类的属性中, 它是通过将 Bean 注入到构造方法的形参上, 然后在构造方法内部将形参的值赋给属性来实现的.

如上图所示, 通过构造方法注入的方式, 成功完成了对属性的注入.

5.2.1 修改默认构造方法

但是, 上述代码中只有一个构造方法, 当存在多个构造方法时, 我们再来观察结果:

发现, 仅仅增加一个无参构造后, 属性的注入就失败了, 这是因为这时 Spring 走的构造方法是无参构造, 而非有参构造. 

当我们使用注解让 Spring 管理 Bean 时, Spring 首先肯定是先创建出这个类的 Bean, 再进行管理. 而 Spring 创建 Bean 时, 是通过反射机制拿到构造方法再创建的, 而 Spring 默认使用的构造方法就是无参构造. 

若类中有多个构造方法, 但没有无参构造, 此时 Spring 就无法确定用哪个构造方法来创建 Bean, 此时程序就会报错.

若类中只有一个构造方法(即使不是无参构造), Spring 也会使用这个构造方法来创建 Bean.

因此, 在上述代码中, 这个类中存在多个构造方法(有参和无参), Spring 默认使用的是无参构造, 因此打印出的属性值为 null.

此时, 我们就可以使用 @Autowired 来手动指定创建 Bean 时的默认构造方法, 将默认构造方法修改为有参构造, 此时就能完成依赖注入了:

5.2.2 总结

  1. 当类中只有一个构造方法时, Spring 就默认使用这个构造方法来创建 Bean, 因此 @Autowired 可以省略不写.
  2. 当类中存在多个构造方法时, Spring 默认使用的是无参构造, 若没有无参构造, 则报错.
  3. 当类中存在多个构造方法时, 可以使用 @Autowired 手动指定默认构造方法.

5.3 setter 方法注入

注意: 使用 setter 进行依赖注入时, 一定要给每一个 setter 方法都加上 @Autowired 注解!!

若不给 setter 方法加注解, 就无法完成注入操作:

5.4 三种注入方式的优缺点

面试可能考.

5.4.1 属性注入

优点: 

  1. 简洁, 使用方便

缺点:

  1. 只能用于 IoC 容器
  2. 不能注入 final 属性

5.4.2 构造方法注入

优点:

  1. 可以注入 final 属性
  2. 注入的 Bean 不会被修改
  3. 依赖(Spring 中的 Bean)在使用前一定会被完全初始化, 因为是在构造方法中执行的, 因此可以安全的在当前类中使用这个被注入的属性, 无需担心空指针异常或其他初始化问题.
  4. 通用性好, 构造方法是 JDK 支持的, 因此任何框架都适用.

缺点:

  1. 需要注入多个 Bean 依赖时, 代码繁琐.

5.4.3 setter 方法注入

优点: 

  1. 对属性完成注入后, 后续可以再使用 setter 方法进行配置或注入

缺点:

  1. 不能注入 final 修饰的属性
  2. setter 方法可以重复使用, 存在属性被修改的风险(既是优点也是缺点)

5.5 @Autowired 存在的问题

上文说到, @Autowired 是根据类型来从 Spring 中获取 Bean 的.

而根据类型来获取 Bean, 只适合于容器中只存在一个该类型的 Bean. 

当容器中存在多个该类型的 Bean 时, 再通过类型进行获取, 就会出现问题:

我们可以通过以下三个注解来解决该问题:

  1. @Primary [Spring 注解]
  2. @Qualifier [Spring 注解]
  3. @Resource [JDK 注解]

5.5.1 @Primary [不常用]

大家看到 Primary 这个词有没有觉得有些眼熟??

每次, 就是我们学习数据库时的 "主键".

Spring 中也是一样, 当容器中存在多个同一类型的 Bean 时, 我们使用 @Primary 将某个 Bean 标记为首选 Bean.

依赖注入时, 即使存在多个该类型的 Bean 也没问题, 优先将这个 Bean 进行注入.

5.5.2 @Qualifier [常用]

@Qualifier 注解可以指定要注入的 Bean 的名称(Bean name).

当存在多个类型匹配的 Bean 时, Spring 容器会根据 @Qualifier 注解中指定的 Bean name, 从容器中选择对应的 Bean, 并将其注入到被 @Autowired 标记的属性中, 从而完成依赖注入.

因此, @Qualifier 可以和 @Autowired 搭配使用, 共同完成依赖注入的操作.

注意, @Qualifier 必须和 @Autowired 搭配使用, 而不能单独使用.

  1. @Autowired 触发依赖注入, 并确定要获取的 Bean 的类型
  2. @Qualifier 不会触发依赖注入, 但能缩小依赖查找的范围

此外, @Qualifier 还可以为参数进行注解, 指定参数被哪个 Bean 注入:

5.5.3 @Resource [常用]

 @Resource 是 JDK 中注解, 而非 Spring 中的注解.

@Resource 可以单独使用, 并且可以通过其 name 属性来指定要进行注入的 Bean 的名称.

因此, @Resource 是根据 类型 + 名称 获取 Bean 的.

我们程序员在进行依赖注入时:

  1. 对属性进行注入时, 通常使用 @Autowired 或者 @Resource [简洁]
  2. 对参数进行注入时, 使用 @Qualifier

5.6 @Autowired 和 @Resource 的区别 [高频面试题]

  1. @Autowired 是 Spring 提供的注解, 而 @Resource 是 JDK 提供的注解
  2. @Autowired 是按照类型注入的, 而 @Resource 是按照名称(Bean name)注入的. [不严谨, 但面试官爱听]

为什么说第二点不严谨呢??

其实, @Autowired 不仅只按照类型注入, 也会按照 参数名称 进行注入, 即容器中存在多个该类型的 Bean 时, Spring 会按照参数名称去容器中获取 Bean, 如果实在获取不到, 再报错(上文有讲):

@Resource 也不仅只按照 Bean name 注入, 而是在确保同一类型的前提下, 再按照 Bean name 注入的.

5.7 @Autowired 装配顺序


END

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2301689.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数字化转型4化:标准化奠基-信息化加速-数字化赋能-智能化引领

​随着经济增速的放缓,大国体系所催生的生产力逐渐释放,后续业务的发展愈发需要精耕细作,精益理念也必须深入企业的骨髓。与此同时,在全球经济一体化的大背景下,企业面临着来自国内外同行,甚至是跨行业的激…

简单易懂,解析Go语言中的Channel管道

Channel 管道 1 初始化 可用var声明nil管道;用make初始化管道; len(): 缓冲区中元素个数, cap(): 缓冲区大小 //变量声明 var a chan int //使用make初始化 b : make(chan int) //不带缓冲区 c : make(chan stri…

C++基础知识学习记录—模版和泛型编程

1、模板 概念: 模板可以让类或者函数支持一种通用类型,在编写时不指定固定的类型,在运行时才决定是什么类型,理论上讲可以支持任何类型,提高了代码的重用性。 模板可以让程序员专注于内部算法而忽略具体类型&#x…

已解决IDEA无法输入中文问题(亲测有效)

前言 在使用IDEA的时候,比如我们想写个注释,可能不经意间,输入法就无法输入中文了,但是在其他地方打字,输入法仍然能够正常工作。这是什么原因呢,这篇文章带你解决这个问题! 快捷键 如果你的I…

人工智能之目标追踪DeepSort源码解读(yolov5目标检测,代价矩阵,余弦相似度,马氏距离,匹配与预测更新)

要想做好目标追踪,须做好目标检测,所以这里就是基于yolov5检测基础上进行DeepSort,叫它为Yolov5_DeepSort。整体思路是先检测再追踪,基于检测结果进行预测与匹配。 一.参数与演示 这里用到的是coco预训练人的数据集: 二.针对检测结果初始化track 对每一帧数据都输出…

Copilot基于企业PPT模板生成演示文稿

关于copilot创建PPT,咱们写过较多文章了: Copilot for PowerPoint通过文件创建PPT Copilot如何将word文稿一键转为PPT Copilot一键将PDF转为PPT,治好了我的精神内耗 测评Copilot和ChatGPT-4o从PDF创建PPT功能 Copilot for PPT全新功能&a…

MySQL 主从复制原理及其工作过程

一、MySQL主从复制原理 MySQL 主从复制是一种将数据从一个 MySQL 数据库服务器(主服务器,Master)复制到一个或多个 MySQL 数据库服务器(从服务器,Slave)的技术。以下简述其原理,主要包含三个核…

MySQL远程连接配置

一、配置TCP服务地址绑定 配置文件路径 /etc/mysql/mysql.cnf /etc/mysql/mysql.conf.d/mysqld.cnf具体文件可以通过 mysql --help查看 配置项 # 只接受本地连接 bind-address 127.0.0.1 mysqlx-bind-address 127.0.0.1改为 # 接受任意IP地址连接 bind-address …

iOS开发书籍推荐 - 《高性能 iOS应用开发》(附带链接)

引言 在 iOS 开发的过程中,随着应用功能的增加和用户需求的提升,性能优化成为了不可忽视的一环。尤其是面对复杂的界面、庞大的数据处理以及不断增加的后台操作,如何确保应用的流畅性和响应速度,成为开发者的一大挑战。《高性能 …

leetcode1047-删除字符串中的所有相邻重复项

leetcode 1047 思路 因为要删除字符串中的所有相邻重复项,那么在删除完成后,最后返回的元素中是不应该存在任何相邻重复项的,如果是普通的遍历,假设str ‘abbaca’,遍历出来只发现中间的bb是相邻重复的删除了以后a…

解决DeepSeek服务器繁忙问题的实用指南

目录 简述 1. 关于服务器繁忙 1.1 服务器负载与资源限制 1.2 会话管理与连接机制 1.3 客户端配置与网络问题 2. 关于DeepSeek服务的备用选项 2.1 纳米AI搜索 2.2 硅基流动 2.3 秘塔AI搜索 2.4 字节跳动火山引擎 2.5 百度云千帆 2.6 英伟达NIM 2.7 Groq 2.8 Firew…

web入侵实战分析-常见web攻击类应急处置实验1

场景说明: 某天运维人员发现在/opt/tomcat8/webapps/test/目录下,多出了一个index_bak.jsp这个文件, 并告诉你如下信息 操作系统:ubuntu-16.04业务:测试站点中间件:tomcat开放端口:22&#x…

【Kubernetes】k8s 部署指南

1. k8s 入门 1.1 k8s 简介 需要最需要明确的就是:kubernetes(简称 k8s ) 是一个 容器编排平台 ,换句话说就是用来管理容器的,相信学过 Docker 的小伙伴对于容器这个概念并不陌生,打个比方:容器…

深度解析:使用 Headless 模式 ChromeDriver 进行无界面浏览器操作

一、问题背景(传统爬虫的痛点) 数据采集是现代网络爬虫技术的核心任务之一。然而,传统爬虫面临多重挑战,主要包括: 反爬机制:许多网站通过检测请求头、IP地址、Cookie等信息识别爬虫,进而限制…

iOS事件传递和响应

背景 对于身处中小公司且业务不怎么复杂的程序员来说,很多技术不常用,你可能看过很多遍也都大致了解,但是实际让你讲,不一定讲的清楚。你可能说,我以独当一面,应对自如了,但是技术的知识甚多&a…

JDK最详细安装教程,零基础入门到精通,收藏这篇就够了

目录 一、下载与安装二、配置环境三、验证是否配置成功 一、下载与安装 1、下载地址 http://www.oracle.com/technetwork/java/javase/downloads/index.html 2、选择自己想要的版本下载,并且选择自己电脑对应的版本下载 3、下载完成之后,双击打开然后…

深研究:与Dify建立研究自动化应用

许多个人和团队面临筛选各种网页或内部文档的挑战,以全面概述一个主题。那么在这里我推荐大家使用Dify,它是一个用于LLM应用程序开发的低代码,开源平台,它通过自动化工作流程的多步搜索和有效汇总来解决此问题,仅需要最小的编码。 在本文中,我们将创建“ Deepresearch”…

新手向:SpringBoot后端查询到数据,前端404?(附联调时各传参方式注解总结-带你一文搞定联调参数)

前言: 在 Spring Boot 项目开发中,后端小伙伴可能经常遇到这样诡异的场景: 后台日志显示查询到了数据,但前端却一脸懵逼地告诉你 404 Not Found?接口明明写好了,Postman 直接访问却提示找不到&#xff1f…

Mysql各操作系统安装全详情

" 至高无上的命运啊~ " MySQL是一个关系型数据库管理系统,由瑞典 MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的RDBMS (Relational Database Mana…

RadASM环境,win32汇编入门教程之七

;运行效果 ;RadASM环境,win32汇编入门教程之七 ;在上一个教程里面,我们学习如何把数据显示出来。但是感觉太丑了,在这一教程里,我们来学习一下怎样让它们变漂亮点。 ;主要的内容是如何创建字体,设置字体的大小&#xf…