当前位置: 首页 > news >正文

告别依赖混乱:Spring IoC 容器与 DI 依赖注入入门精讲

目录

什么是 IoC

IoC 介绍

传统开发思路

解决方法

IoC 优势

DI

IoC & DI 使用

IoC 详解

Bean 的存储

@Controller(控制器存储)

获取 bean 对象的其他方法

bean 命名

面试题之 ApplicationContext  pk BeanFactory

@Service(服务存储)

@Respository(仓库存储)

@Component(组件存储)

@Configuration(配置存储)

为什么这么多类注解?

方法注解 @Bean

定义多个对象

扫描路径

DI 详解

属性注入(Field Injection)

构造方法注入(Constructor Injection)

Setter 注入(Setter Injection)

三种注入方式的优缺点

@Autowired 存在的问题

使用@Primary:

 @Qualifier 注解:

@Resource 注解:

面试题之 @Autowird 与 @Resource 的区别

Spring,Spring Boot ,Spring MVC

完!


Spring 是包含了众多工具方法的 IoC 容器

List/Map -> 数据存储容器

Tomcat -> Web 容器

什么是 IoC

我们在前面已经使用过 IoC 了,在类上面添加 @RestController 和 @Controller 注解,就是把这个对象交给 Spring 管理,Spring 框架启动的时候,就会加载该类,把对西昂交给 Spring 管理,就是 IoC 思想。

IoC:Inversion of Control(控制反转),也就是说,Spring 是一个 “控制反转” 的容器。

控制反转什么呢??? 获得依赖对象的过程被反转了。也就是说,当需要某个对象的时候,传统开发中,需要我们自己 new 一个对象,现在不需要再进行创建了,把创建对象的任务交给了容器。我们在程序中,只需要进行依赖注入即可~~ 这个容器,就称为 IoC 容器,所以有时 Spring 也被称为 Spring 容器。

IoC 介绍

我们以一个具体案例来了解 IoC 思想。

当我们需要造一辆车的时候。

传统开发思路

先设计轮子,然后根据轮子的大小设计底盘,再根据底盘设计车身,再根据车身,对整个汽车进行设计。这样一层一层设计,就会出现一个依赖关系 ,即汽车依赖车身,车身依赖底盘,底盘依赖轮子。

上面的设计的可维护性非常低。当我们的需求发生一些变化的时候,随着对车的需求量越来越大,个性化需求也会越来越多,需要加工更多尺寸的轮胎,就需要对程序进行修改了。

即问题是:当最底层的代码发生改动之后,调用链上的所有代码,都需要进行修改。程序的耦合度极高,修改一处代码,会影响其他处的代码~~

解决方法

上面程序中,我们根据轮子的尺寸设计底盘,轮子尺寸修改,底盘就需要修改,同样的,后面的车身,汽车都需要修改。

我们可以先设计汽车的大概样子,然后根据汽车来设计车身,根据车身设计底盘,根据底盘设计轮子。

我们可以尝试,不在每个类中创建自己的下积累,如果自己创建下级类,当下级类发生改变操作的时候,我们自己也要跟着修改。

改用传递(注入)的方式。

IoC 优势

传统代码中创建对象的顺序是:Car->Framework->Bottom->Tire

改进解耦合之后的顺序是:Tire->Bottom->Framework->Car

改进之后,创建对象的控制权发生了反转,不再是使用方来进行对象创建并且控制依赖对象了,而是把依赖对象注入到当前对象中,依赖对象的控制权不再由当前类进行控制了。

这部分代码,就算 IoC 容器所作的工作。

IoC 容器可进行资源的几种管理,实现资源的可配置和易管理,当我们需要使用的时候,只需要从容器中取就可以了

IoC 容器也降低了使用资源双方的依赖程度,创建实例的时候并不需要了解细节,实现了解耦合~~

DI

DI:Dependency Injection (依赖注入)

容器在运行期间,动态的为应用程序提供运行时所依赖的资源。依赖注入是从应用程序的角度进行描述,指通过引入 IoC 容器,利用依赖关系注入的方式,实现对象之间的解耦合

IoC & DI 使用

Spring 是一个 IoC 容器,管理的主要是对象,这些对象,我们称之为 Bean。Spring 来负责这些对象的创建和销毁,我们程序只需要告诉 Spring,那些需要存,以及如何从 Spring 中取出对象。

实现:

1. 把 BookDao 交给 Spring 管理,在 BookDao 类前添加 @Component 注解

2. 把 BookService 交给 Spring 管理,由 Spring 来管理对象

3. 删除 BookService 中创建 BookDao 的代码,从 Spring 中获取对象,添加 @Autowired 注解

4. 删除 BookController 中创建 BookService 的代码,从 Spring 中获取对象,添加 @Autowried 注解

IoC 详解

系统的学习 Spring IoC 和 DI 操作。前面提到的 IoC 控制反转,就是将对象的控制权交给 Spring 的 IoC 容器,由它对对象进行创建和管理。

也就是 bean 的存储。

Bean 的存储

之前的案例中,我们要把对象交给 IoC 容器管理,需要在类上添加一个注解:@Component 

Spring 框架中,提供了更丰富的注解。

@Controller(控制器存储)

从 Spring 容器中获取对象

补充:因为我们的对象通过 @Controller 注解都交给 Spring 管理了,所以获取对象要通过 Spring 获取,那么就需要先得到 Spring 的上下文,即 ApplicationContext 翻译就是 Spring 上下文~

此时,如果我们把 @Controller 删掉,运行结果如下:

表明在 Spring 中找不到指定类型的 Bean

获取 bean 对象的其他方法

通常使用 1 2 4 三种方式获取 bean,且获取到的 bean 都是一致的

其中 1 2 都涉及到根据名称来获取对象,再来研究一下 bean 命名约定~

bean 命名

官方文档中写道:程序开发人员并不需要为 bean 指定名称,如果没有显示的提供名称,Spring 容器会为该 bean 生成唯一的名称。

命名约定就使用 Java 标准约定作为实例字段名。即,bean 名称以小写字母开头,然后使用驼峰式大小写~

也有特殊情况,即,当由多个字符,且第一个和第二个字符都是大写的时候,将会保留原始的大小写~

我们根据规则,再来进行 bean 的获取:

三条 sout 语句的结果一致

地址一样,说明对象是同一个~

面试题之 ApplicationContext  pk BeanFactory

继承关系和功能方面:Spring 容器的两个顶级的接口:BeanFactory 和 ApplicationContext。其中,BeanFactory 提供了基础的访问容器的能力,ApplicationContext 属于 BeanFactory 的子类,出了继承了 BeanFactory 的功能之外,还有了其他方面的特性~

性能方面:BeanFactory 是懒加载,用到那个加载那个。ApplicationContext 是一次性加载并初始化所有的 Bean 对象~

@Service(服务存储)

去掉 @service 注解后,仍然报错:

@Respository(仓库存储)

@Component(组件存储)

@Configuration(配置存储)

为什么这么多类注解?

@Controller:控制层,接收请求,对请求进行处理,并进行响应。

@Service:业务逻辑层,处理具体的业务逻辑。

@Respository:数据访问层,负责数据访问操作

@Configuration:配置层,处理项目中的一些配置信息

当我们对五大类注解的源码进行观察后

除 @component 之外,剩下四个注解的源码中均有 @Component 注解。说明他们本身都是属于 @Component 的子类,@Component 是一个元注解,可以对其他注解进行注解~~

剩下四个注解,可以被称为 @Component 的衍生注解~~

其实从功能上来说,五大注解大差不多可以混用,但是在逻辑上是不可以的~~

方法注解 @Bean

类注解是添加到某个类上的,但有两个问题:

        1. 使用外部包中的类,没办法添加类注解

        2. 一个类,需要多个对象,多个数据源~

这种情况,我们需要使用 @Bean 注解

 

结果如下:

方法注解是要配合类注解进行使用的。

在 Spring 框架的设计中,方法注解 @Bean 要配合类注解才能将对象正常的存储到 Spring 容器中

定义多个对象

即,多数据源的情况,类是同一个,但配置不同,指向不同的数据源

此时,我们根据类型获取对象:

运行结果:

期望是获取到唯一一个匹配,结果发现了两个 user1 和 user2

从报错信息来分析,@Bean 注解的 bean,其名称就是它的方法名。

根据名称来获取 bean 对象:

此时可以成功获取到~

也可以对 bean 的名称进行重命名

扫描路径

Q:使用前面我们提到的四个注解生命的 bean,一定会生效吗?

A:不一定(bean 要想生效,还需要被 Spring 扫描到)

其他代码不懂,仅仅修改目录结构:

又会发现,找不到名称为 u1 的 bean。

使用五大注解声明的 bean,要想生效,还需要配置扫描路径,让 Spring 扫描到这些注解~

使用 @ComponentScan 来配置扫描路径

这种做法仅作了解~

那为什么前面我们并没有配置这个直接,也可以正常使用呢?

@SpringBookApplication 这个启动类声明注解中,已经包含 @ComponentScan 注解了~

会默认扫描 SpringBoot 启动类所在的包及其子包~

一般我们将启动类直接放在我们要被扫描的包的路径下即可~

DI 详解

依赖注入是一个过程,值 IoC 容器在创建 Bean 的时候,去提供运行时所依赖的资源(对象)

上面案例中,我们是使用了  @Autowired 注解,完成了依赖注入的操作。

简单来说,就是把对象取出来,放入某个类的属性中。

依赖注入,Spring 也提供了三种方式

属性注入(Field Injection)

属性注入是使用 @Autowired 实现的,将 Service 类注入到 Controller 类中

运行结果:

去掉 @Autowired 的时候,结果如下:空指针异常,找不到 userService

构造方法注入(Constructor Injection)

注:

        1. 如果只有一个构造函数的情况下,@Autowired 可以省略

        2. 如果有多个构造函数,需要指定默认的构造函数(@Autowired 指定)如果未指定,则默认使用无参的构造函数

        3. 构造函数规范:如果添加构造函数,把无参构造函数显示的进行添加~

Setter 注入(Setter Injection)

Setter 注入和属性的 Setter 方法实现类似,只不过在设置 set 方法时候,需要加上 @Autowired 注解

三种注入方式的优缺点

@Autowired 存在的问题

当同一个类中,存在多个 bean 的时候,使用 @Autowired 会存在问题

运行结果:

报错的原因是:非唯一的 Bean 对象

解决方案:

@Primary

@Qualifier

@Resource

使用@Primary

当存在多个相同类型的 Bean 注入时候,加上 @Primary 注解,来确认默认的实现~

 @Qualifier 注解

指定当前要注入的 bean 对象。在 @Qualifier 的 value 属性中,指定注入的 bean 的名称

注:Qualifier 注解不能单独使用,需要搭配 @Autowired 使用

@Resource 注解:

是按照 bean 的名称进行注入。通过 name 属性指定要注入的 bean 的名称

面试题之 @Autowird 与 @Resource 的区别

1. @Autowired 是 Spring 框架提供的注解,而 @Resource 是 jdk 提供的注解

2 @Autowired 默认是按照类型注入的,而 @Resource 是按照名称注入,相比 @Autowired 来说,@Resource 支持更多的参数设置~

Spring,Spring Boot ,Spring MVC

 

完!


文章转载自:

http://PoEnnvvz.brbnc.cn
http://pHHYe0xF.brbnc.cn
http://bTpfV3Uh.brbnc.cn
http://VY0oQlMY.brbnc.cn
http://bsKlrEXv.brbnc.cn
http://DIuLAL40.brbnc.cn
http://YTdvwCtR.brbnc.cn
http://Xv2D4ENP.brbnc.cn
http://N9aAXzKA.brbnc.cn
http://Lo8YgSbT.brbnc.cn
http://decO6Emi.brbnc.cn
http://stPvCM14.brbnc.cn
http://mKbzvWyH.brbnc.cn
http://RXuyDF7Q.brbnc.cn
http://YiytzGyV.brbnc.cn
http://rE2e6nDh.brbnc.cn
http://t3QFMp9K.brbnc.cn
http://RKHGkM6v.brbnc.cn
http://MK2g4KUB.brbnc.cn
http://Uu5f1z9h.brbnc.cn
http://u6sLcUgH.brbnc.cn
http://EoUKoJEX.brbnc.cn
http://b5xyaAZ9.brbnc.cn
http://eN2eAFUk.brbnc.cn
http://NPbWmM6D.brbnc.cn
http://EC5WfXvW.brbnc.cn
http://ROhio34R.brbnc.cn
http://v6DsMK50.brbnc.cn
http://FzhPvAZL.brbnc.cn
http://FXUDNf4H.brbnc.cn
http://www.dtcms.com/a/388667.html

相关文章:

  • Python爬虫实战——使用NetNut网页解锁器获取亚马逊电商数据的高级策略与实践
  • 黑马JavaWeb+AI笔记 Day11 Web后端实战(登录模块)
  • Nocobase如何优雅的设置动态的自定义存储路径
  • 线性回归与 Softmax 回归:深度学习基础模型及训练逻辑解析
  • 第四章:职业初印象:打造你的个人品牌(3)
  • 大模型学习:什么是FastText模型架构
  • 【人工智能通识专栏】第十八讲:作业辅导提升
  • Python Matplotlib 布局
  • PHP自动计算文件大小,如:KB、MB、TB等
  • K近邻:从理论到实践
  • 微服务高可用流程讲解
  • 云HIS系统,HIS源码,基于云计算技术的医院信息管理平台,采用B/S架构和微服务技术开发,支持SaaS应用模式。
  • 【卷积神经网络详解与实例】10——经典CNN之GoogLeNet
  • C# 委托和事件详解,委托 vs 方法封装解析
  • MariaDB源码编译安装
  • 多智能体编排之王:深度解析微软Semantic Kernel的AgentOrchestration架构革命
  • AI工具推荐之ezremove.ai
  • 关于Address Editor中修改基地址和地址空间的指南
  • 【Linux 系统探幽:从入门到内核・系统编程开篇】基础指令与权限精讲,筑牢系统开发根基
  • 【STL库】哈希封装 unordered_map/unordered_set
  • 【AI编程】Qoder AI 编程工具从部署到深度使用实战详解
  • 网络原理——数据链路层
  • 大语言模型的 “幻觉” 难题:技术成因、解决方案与应用风险规避
  • 状态保留功耗门控 SRPG (State Retention Power Gating)
  • Elman神经网络多输入多输出回归预测+SHAP可解释分析+新数据预测(MATLAB源码)
  • 408 王道数据结构的学习记录
  • 使用内存映射读取文件和写入文件,并进行性能测试
  • SQL的UNION用法大全介绍
  • 从Web原生到高性能:如何优化企业数据库管理工具
  • 基于python新能源汽车数据分析可视化系统 懂车帝 Scrapy爬虫 Django框架 Vue框架 大数据项目(源码+文档)✅