【spring】IOC与DI

💐个人主页:初晴~

📚相关专栏:程序猿的春天


一、IOC(Inversion of Control)

1、概念

IOC(Inversion of Control,控制反转)是一种设计原则,它将对象的控制权从程序代码中转移到外部容器中。比如在类上⾯添加 @RestController 和 @Controller 注解,就是把这个对象交给Spring管理,Spring 框架启动时就会加载该类。把对象交给Spring管理,就是IoC思想。

2、具体分析

比如我们有一个需求是:造一辆车

(1)传统开发过程

先设计轮⼦(Tire),然后根据轮⼦的⼤⼩设计底盘(Bottom),接着根据底盘设计⻋⾝(Framework),最后根据⻋⾝设计好整个汽⻋(Car)。这⾥就出现了⼀个"依赖"关系:汽⻋依赖⻋⾝,⻋⾝依赖底盘,底盘依赖轮⼦

代码如下:

public class CarExample {public static void main(String[] args) {Car car = new Car();car.run();}/*** 汽⻋对象*/static class Car {private Framework framework;public Car() {framework = new Framework();System.out.println("Car init....");}public void run(){System.out.println("Car run...");}}/*** ⻋⾝类*/static class Framework {private Bottom bottom;public Framework() {bottom = new Bottom();System.out.println("Framework init...");}}/*** 底盘类*/static class Bottom {private Tire tire;public Bottom() {this.tire = new Tire();System.out.println("Bottom init...");}}/*** 轮胎类*/static class Tire {// 尺⼨private int size;public Tire(){this.size = 17;System.out.println("轮胎尺⼨:" + size);}}
}

这样设计确实可以实现我们的需求。但是可维护性非常低。当我们需要更改某一个需求时,就很有可能会“牵一发而动全身”。

比如当我们需要定制各种尺寸的轮胎时,轮胎的尺寸就需要修改为变量:

但是由于这种开发方式的耦合调用关系,只改轮胎的代码肯定会导致其它依赖的程序出现报错,就需要继续修改:

由以上例子我们不难看出,传统的开发方式各个类的耦合程度过高,各个类直接相互依赖,当某个类需要发生改变时,整个调⽤链上的所有代码都需要修改

(2)IOC开发方式

我们可以先设计汽⻋的⼤概样⼦,然后根据汽⻋的样⼦来设计⻋⾝,根据⻋⾝来设计底盘,最后根据底盘来设计轮⼦。这时候,依赖关系就倒置过来了:轮⼦依赖底盘, 底盘依赖⻋⾝,⻋⾝依赖汽⻋:

如图,改进之后的控制权发生了翻转,不再是使用方创建并控制对象,而是把依赖对象注入到当前的对象,依赖对象的控制权不再由当前类控制,而是交由一个统一的类进行管理:

public class Main {public static void main(String[] args) {Tire tire=new Tire(20);Bottom bottom=new Bottom(tire);Framework framework=new Framework(bottom);Car car = new Car(framework);car.run();}
}
public class Tire {// 尺⼨private int size;public Tire(int size){this.size = size;System.out.println("轮胎尺⼨:" + size);}
}
public class Bottom {private Tire tire;public Bottom(Tire tire) {this.tire = tire;System.out.println("Bottom init...");}
}
public class Framework {private Bottom bottom;public Framework(Bottom bottom) {this.bottom = bottom;System.out.println("Framework init...");}
}
public class Car {private Framework framework;public Car(Framework framework) {this.framework = framework;System.out.println("Car init....");}public void run(){System.out.println("Car run...");}
}

3、优势

1、降低耦合度

  • 通过将对象的创建和依赖关系的管理交给外部容器,减少了代码之间的直接依赖,使得系统更加模块化。

2、提高代码可维护性

  • 由于对象之间的依赖关系是通过配置文件或注解定义的,修改这些依赖关系时不需要修改代码,只需要调整配置,这使得代码更容易维护。

3、提高代码的可重用性

  • 由于对象的创建和依赖关系管理被外部化,相同的对象可以在不同的上下文中重用,而不需要修改代码。

4、Spring中运用IOC

Spring 就是⼀种IoC容器,帮助我们来做了这些资源管理。一般就是通过注解的形式, 将对象的控制权交给Spring的IOC容器,由IOC容器创建及管理对 象。
(1)类注解:
  • @Controller:控制层,接收请求,对请求进⾏处理,并进⾏响应
  • @Servie:业务逻辑层,处理具体的业务逻辑
  • @Repository:数据访问层,也称为持久层。负责数据访问操作
  • @Configuration:配置层。处理项⽬中的⼀些配置信息

其实这几个注解的作用基本都是一致的,之所以要进行区分,主要是为了对类的用途进行分类,让代码结构更加清晰:

观察这几个注解的源码我们会发现:

它们底层都有一个 @Component 注解,这是一个元注解,是真正完成控制反转的注解。理论上,上述所有注解都可以用 @Component 直接代替。不过,为了让开发更加规范,还是建议运用对应的注解比较合适。

(2)方法注解

类注解是添加到某个类上的, 但是存在两个问题:
1. 使⽤外部包⾥的类, 没办法添加类注解
2. ⼀个类, 需要多个对象, ⽐如多个数据源
这种场景, 我们就需要使⽤⽅法注解 @Bean
需要注意的是,⽅法注解 @Bean 也要搭配 类注解进行使用:
@Component
public class BeanConfig {@Bean()public User user(){User user = new User();user.setName("zhangsan");user.setAge(18);return user;}
}

运行结果:

在获取bean时也可以有两种方式:
  • 根据类型获取bean
User user = context.getBean(User.class);
  • 根据名称获取bean
User user1 = (User) context.getBean( "user1" );
还可以通过设置name属性来给 Bean 对象进行重命名操作:
@Component
public class BeanConfig {//@Bean(name={"u1","user1"}) //完整写法//@Bean({"u1","user1"})      //可省略“name=”@Bean("u1")                  //当重命名参数只有一个时,还可省略{}public User user1(){User user = new User();user.setName("zhangsan");user.setAge(18);return user;}
}

二、DI(Dependency Injection)

1、概念

DI,即依赖注入(Dependency Injection),是一种实现控制反转(IOC)原则的技术手段。

容器在运⾏期间, 动态的为应⽤程序提供运⾏时所依赖的资源,称之为依赖注⼊。
可以这样理解:IOC是一种思想,而DI则是具体实现

2、实现方式

(1)属性注入

属性注⼊是使⽤ @Autowired 实现的,将 Service 类注⼊到 Controller 类中
@Controllerpublic class UserController {//注⼊⽅法1: 属性注⼊@Autowiredprivate UserService userService;public void sayHi(){System.out.println("hi,UserController...");userService.sayHi();}
}
(2)构造⽅法注⼊
构造⽅法注⼊是在类的构造⽅法中实现注⼊,如下代码所⽰:
@Controller
public class UserController2 {//注⼊⽅法2: 构造⽅法private UserService userService;@Autowiredpublic UserController2(UserService userService) {this.userService = userService;}public void sayHi(){System.out.println("hi,UserController2...");userService.sayHi();}
}
注意: 如果类只有⼀个构造⽅法,那么 @Autowired 注解可以省略;如果类中有多个构造⽅法,那么需要添加上 @Autowired 来明确指定到底使⽤哪个构造⽅法。

(3)Setter 注⼊

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

解 ,如下代码所⽰:
@Controller
public class UserController3 {//注⼊⽅法3: Setter⽅法注⼊private UserService userService;@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}public void sayHi(){System.out.println("hi,UserController3...");userService.sayHi();}
}

3、三种注⼊优缺点分析

(1)属性注⼊

优点:
  • 简洁,使⽤⽅便;

缺点:

  • 只能⽤于 IoC 容器,如果是⾮ IoC 容器不可⽤,并且只有在使⽤的时候才会出现 NPE(空指 针异常)
  • 不能注⼊⼀个Final修饰的属性
(2)构造函数注⼊(Spring 4.X推荐)

优点:

  • 可以注⼊final修饰的属性
  • 注⼊的对象不会被修改
  • 依赖对象在使⽤前⼀定会被完全初始化,因为依赖是在类的构造⽅法中执⾏的,⽽构造⽅法是在类加载阶段就会执⾏的⽅法.
  • 通⽤性好, 构造⽅法是JDK⽀持的, 所以更换任何框架,他都是适⽤的
缺点:
  • 注⼊多个对象时, 代码会⽐较繁琐
(3)Setter注⼊(Spring 3.X推荐)
优点:
  • ⽅便在类实例之后, 重新对该对象进⾏配置或者注⼊
缺点:
  • 不能注⼊⼀个Final修饰的属性
  • 注⼊对象可能会被改变, 因为setter⽅法可能会被多次调⽤, 就有被修改的⻛险

4、@Autowired存在问题

当同⼀类型存在多个bean时, 使⽤@Autowired会存在问题
@Component
public class BeanConfig {@Bean("u1")public User user1(){User user = new User();user.setName("zhangsan");user.setAge(18);return user;}@Beanpublic User user2() {User user = new User();user.setName("lisi");user.setAge(19);return user;}
}@Controller
public class UserController {//注入user@Autowiredprivate User user;public void sayHi(){System.out.println("hi,UserController...");System.out.println(user);}
}
运行结果:

报错的原因是,⾮唯⼀的 Bean 对象。
对此,Spring有三种解决方式:
(1) 使⽤@Primary注解
当存在多个相同类型的Bean注⼊时,加上@Primary注解,来确定默认的实现
@Component
public class BeanConfig {@Primary //指定该bean为默认bean的实现@Bean("u1")public User user1(){User user = new User();user.setName("zhangsan");user.setAge(18);return user;}@Beanpublic User user2() {User user = new User();user.setName("lisi");user.setAge(19);return user;}
}

(2)使用@Qualifier注解

指定当前要注⼊的bean对象。 在@Qualifier的value属性中,指定注⼊的bean的名称。
注意: @Qualifier注解不能单独使⽤,必须配合@Autowired使⽤
@Controller
public class UserController {//注⼊user@Qualifier("user2")@Autowiredprivate User user;public void sayHi(){System.out.println("hi,UserController...");System.out.println(user);}
}

(3)使⽤@Resource注解

按照bean的名称进⾏注⼊。通过name属性指定要注⼊的bean的名称
@Controller
public class UserController {//注⼊user@Resource(name = "user2")private User user;public void sayHi(){System.out.println("hi,UserController...");System.out.println(user);}
}

5、@Autowird 与 @Resource的区别

  • @Autowired是spring框架提供的,@Resource是JDK提供的注解
  • @Autowired默认是按类型注入的,而@Resource优先是按照名称注入的,@Resource提供更多的参数设置
@Autowired装配顺序


那么本篇文章就到此为止了,如果觉得这篇文章对你有帮助的话,可以点一下关注和点赞来支持作者哦。如果有什么讲的不对的地方欢迎在评论区指出,希望能够和你们一起进步✊

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

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

相关文章

【英特尔IA-32架构软件开发者开发手册第3卷:系统编程指南】2001年版翻译,2-16

文件下载与邀请翻译者 学习英特尔开发手册,最好手里这个手册文件。原版是PDF文件。点击下方链接了解下载方法。 讲解下载英特尔开发手册的文章 翻译英特尔开发手册,会是一件耗时费力的工作。如果有愿意和我一起来做这件事的,那么&#xff…

​​​​​​​PHP类型比较

在php中符号分为两种,一种是,还是一种是 松散比较:使用两个等号 比较,只比较值,不比较类型。 严格比较:用三个等号 比较,除了比较值,也比较类型。 注意,当一个号时&…

Mysql、Dm8达梦数据库通过脚本导出指定库所有表的结构详情信息到

目录 前言二、Mysql三、达梦8 前言 在当今复杂多变的数据环境中,数据库作为信息存储与管理的核心,其重要性不言而喻。随着业务的不断拓展和深化,对于数据库表结构的理解与管理成为了确保数据一致性和准确性的关键。特别是在跨数据库系统的场…

yelp数据集上识别潜在的热门商家

yelp数据集是研究B2C业态的一个很好的数据集,要识别潜在的热门商家是一个多维度的分析过程,涉及用户行为、商家特征和社区结构等多个因素。从yelp数据集里我们可以挖掘到下面信息有助于识别热门商家 用户评分和评论分析 评分均值: 商家的平均评分是反映其…

文献阅读记录6-Toward computer-made artificial antibiotics

摘要 将合成生物学和计算生物学的概念结合起来,可能会产生比现有药物更不容易产生耐药性的抗生素,而且还能对抗耐药感染。事实上,计算机引导策略与大规模并行高通量实验方法相结合,代表了抗生素发现的新范式。耐多药微生物引起的…

【docker compose】docker compose的hello world

安装docker desktop后在终端使用以下命令,代表安装成功,并查看当前安装的版本 docker-compose --version示例docker-compose.yml文件 version: 3.8 # 指定 Docker Compose 文件的版本services:scau_jwc: # 定义一个名为 scau_jwc 的服务image: scau_…

PyTorch核心概念:从梯度、计算图到连续性的全面解析(二)

文章目录 pytorch中的Autograd计算图叶子张量 inplace操作PyTorch的两大特点动态图eager execution PyTorch中的Variable参考文献 pytorch中的Autograd pytorch提供了自动求导机制和对GPU的支持 了解自动求导背后的原理和规则:当使用pytorch中没有的loss function时…

dayseven-因果分析-图模型与结构因果模型

在数学上,​“图”(graph)是顶点(vertex,也可以称为节点)和边(edge)的集合,表示为图G(V,E),其中V是节点的集合,E是边的集合,图中的节点之间通过边相连(也可以不相连&…

今天强的可怕,AI文风写作再也不用写指令了

AI写作最有用的事情之一就是捕捉特定的写作风格,市面上写作工具模仿文风需要下达复杂的prompt,经过一大段精细的微调才能实现! 而现在文思助手只要一个按钮就能输出一篇文风相似的文章!超级简单,你再也不用为一大段一大…

Vue2中使用firefox的pdfjs进行文件文件流预览

文章目录 1.使用场景2. 使用方式1. npm 包下载,[点击查看](https://www.npmjs.com/package/pdfjs-dist)2. 官网下载1. 放到public文件夹下面2. 官网下载地址[点我,进入官网](https://github.com/mozilla/pdf.js/tags?afterv3.3.122) 3. 代码演示4. 图片预览5. 如果遇到跨域或者…

哪些因素会影响 DC/DC 转换电路快速测试的性能?-纳米软件

DC/DC 转换电路在现代电子设备中起着至关重要的作用,其性能的快速准确测试对于确保电子系统的可靠性和稳定性至关重要。然而,有许多因素会影响 DC/DC 转换电路快速测试的性能。 电路复杂性和参数多样性 单片 DC/DC 转换器由于功能模块和参数复杂性&…

解线性方程组(二)

实验类型:●验证性实验 ○综合性实验 ○设计性实验 实验目的:进一步熟练掌握用Jacobi迭代法和Gauss-Seidel法解线性方程组的算法,提高编程能力和解算线性方程组问题的实践技能。 实验内容: 1)取初值性x(0)(0,0,0,0)T, 精度要求ε…

跨境电商营销:Pinterest的5个便捷营销工具

Pinterest是消费者寻找创意灵感的首选平台之一,同时,根据Global Web Index的调查数据,人们使用Pinterest的首要原因是寻找新产品和品牌,这意味着用户在使用Pinterest时已经有消费意愿和倾向。 因此,让更多目标受众注意…

JAVA基础:多重循环、方法、递归 (习题笔记)

一&#xff0c;编码题 1.打印九九乘法表 import java.util.*;public class PanTi {public static void main(String[] args) {Scanner input new Scanner(System.in);for (int i 0; i < 9; i) {//i控制行数/* System.out.println("。\t。\t。\t。\t。\t。\t。\t。\…

小林渗透入门:burpsuite+proxifier抓取小程序流量

目录 前提&#xff1a; 代理&#xff1a; proxifier&#xff1a; 步骤&#xff1a; bp证书安装 bp设置代理端口&#xff1a; proxifier设置规则&#xff1a; proxifier应用规则&#xff1a; 结果&#xff1a; 前提&#xff1a; 在介绍这两个工具具体实现方法之前&#xff0…

[笔记] Centos7 安装 Docker 和 Docker Compose 及 Docker 命令大全

Docker 和 Docker Compose 是相辅相成的工具&#xff0c;它们共同提供了一个强大的容器化解决方案。Docker 提供了容器化的基础功能&#xff0c;而 Docker Compose 则提供了更高级的编排和管理能力&#xff0c;使得部署和管理多个容器变得更加容易和高效。 Docker&#xff1a;…

el-message 同时弹出多个【改写el-message】

因为服务断开了 但是拦截器里对每个失败的接口都做了message弹出&#xff0c;因此改写el-message逻辑&#xff0c;仅展示一个同等类型的message窗体 1. 新建 /utils/rewriteElMessage.js /*** Event 解决 el-message 同类型重复打开的问题* description:* author: mhf* time:…

SSM宿舍管理系统-计算机毕业设计源码03732

目 录 1 绪论 1.1研究背景 1.2开发现状 1.3研究内容 1.4论文结构与章节安排 2 宿舍管理系统系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 数据流程 3.3.2 业务流程 2.3 系统功能分析 2.3.1 功能性分析 2.3.2 非功能性分析 2.4 系统用例分析 2.5本章小结 3 …

淘宝商品描述,一键“爬”回家 —— Java爬虫的奇妙冒险

引言&#xff1a; 在这个信息爆炸的时代&#xff0c;我们每天都在被各种商品信息轰炸。你是否曾想过&#xff0c;如何能快速、准确地获取淘宝商品的描述信息&#xff1f;今天&#xff0c;就让我们一起开启一段Java爬虫的奇妙冒险&#xff0c;探索如何通过代码一键“爬”取淘宝…