【Java开发】Spring 12 :Spring IOC控制反转和依赖注入(解决单接口多实现类调用)

news2024/11/14 21:36:34
IOC 是 Inversion of Control 的简写,译为“控制反转”,Spring 通过 IOC 容器来管理所有 Java 对象的实例化和初始化,控制对象与对象之间的依赖关系。我们将由 IOC 容器管理的 Java 对象称为 Spring Bean,它与使用关键字 new 创建的 Java 对象没有任何区别。

1 控制反转(IOC)

抛开Spring等框架,一个类想要调用另一个类中的属性或方法,通常会先在其代码中通过 new Object() 的方式将后者的对象创建出来,然后才能实现属性或方法的调用,那么调用类掌握着被调用类的控制权

在 Spring 应用中,Java 对象创建的控制权是掌握在 IOC 容器手里的,也就是说 IOC 容器掌握着这些被调用类的控制权。其步骤如下:

  1. 开发人员通过 XML 配置文件、注解、Java 配置类等方式,对 Java 对象进行定义,例如在 XML 配置文件中使用 <bean> 标签、在 Java 类上使用 @Component 注解等。

  1. Spring 启动时, IOC 容器会自动根据对象定义,将这些对象创建并管理起来。这些被 IoC 容器创建并管理的对象被称为 Spring Bean。

  1. 当我们想要使用某个 Bean 时,可以直接从 IOC 容器中获取(例如通过 ApplicationContext 的 getBean() 方法),而不需要手动通过代码(例如 new Obejct() 的方式)创建。

IOC 使得应用开发从思想层面上发生了“主从换位”的改变。原本调用者是主动的一方,它想要使用什么资源就会主动出击,自己创建;但在 Spring 应用中,IOC 容器掌握着主动权,调用者则变成了被动的一方,被动的等待 IOC容器创建它所需要的对象(Bean)。

这个过程在职责层面发生了控制权的反转,把原本调用者通过代码实现的对象的创建,反转给 IoC 容器来帮忙实现,因此我们将这个过程称为 Spring 的“控制反转”,它最大的优势在于解耦合

1.1 IOC 的工作原理

软件开发过程中,各对象和模块间不可避免地存在一定地耦合关系(比如B调用A,C调用B,A调用C),若一个系统的耦合度过高,那么就会造成难以维护的问题,但完全没有耦合的代码几乎无法完成任何工作。因此我们在程序设计时,所秉承的思想一般都是在不影响系统功能的前提下,最大限度的降低耦合度。

IoC 底层通过工厂模式、Java 的反射机制、XML 解析等技术,将代码的耦合度降低到最低限度,其主要步骤如下:

  1. 在配置文件(例如 Bean.xml)中,对各个对象以及它们之间的依赖关系进行配置;

  1. 我们可以把 IOC 容器当做一个工厂,这个工厂的产品就是 Spring Bean;

  1. 容器启动时会加载并解析这些配置文件,得到对象的基本信息以及它们之间的依赖关系;

  1. IoC 利用 Java 的反射机制,根据类名生成相应的对象(即 Spring Bean),并根据依赖关系将这个对象注入到依赖它的对象中。

由于对象的基本信息、对象之间的依赖关系都是在配置文件中定义的,并没有在代码中紧密耦合,因此即使对象发生改变,IOC都会自动在配置文件中进行修改, Java 代码(涉及调用关系)则不需要变动,这就是 Spring IoC 实现解耦的原理。

1.2 以@Component举例

关于实现控制反转,将类Spring Bean注入到IOC容器中,主要有以下注解:

  • @controller :用于标注控制层;

  • @service :用于标注服务层,主要用来进行业务的逻辑处理;

  • @repository:用于标注数据访问层,也可以说用于标注数据访问组件,即DAO组件;

  • @component:用于标注各种组件,若该类不同于以上归类,可使用该注解。

那么如果想将对应的Spring Bean从IOC容器中取出来,一般是用 @Autowired或 @Resourse注解,这将在依赖注入部分进行举例。

首先创建一个类,然后以new形式和@Component注解形式分别解释

① 创建Called类

编写该类的无参构造,若该类被调用,就会在控制台上输出"该类被创建成功"

public class Called {

    public Called(){
        System.out.println("该类被创建成功");
    }
}

② new方式创建对象

我们在Call类中的main方法中new一个Called对象

public class Call {

    public static void main(String[] args) {
        Called called = new Called();
    }
}

执行main方法,输出成功,说明Called对象创建成功👇

③ 给Called类标注@Component注解

@Component
public class Called {

    public Called(){
        System.out.println("该类被创建成功");
    }
}

④ 执行项目启动类

控制台输出成功,说明项目启动后Called类已作为Spring Bean注入Spring的IOC容器👇

2 依赖注入(DI)

依赖注入(Denpendency Injection,简写为 DI)是 Martin Fowler 在 2004 年在对“控制反转”进行解释时提出的。Martin Fowler 认为“控制反转”一词很晦涩,无法让人很直接的理解“到底是哪里反转了”,因此他建议使用“依赖注入”来代替“控制反转”。

在面向对象中,对象和对象之间是存在一种叫做“依赖”的关系。简单来说,依赖关系就是在一个对象中需要用到另外一个对象,即对象中存在一个属性,该属性是另外一个类的对象,比如A调用B,那么可以说A依赖B。

依赖注入本质上是Spring Bean属性注入的一种,只不过这个属性是一个对象属性而已

我在这边加大点难度,以“调用类->接口->实现类(最终的被调用方)“形式,可能需要一点关于接口的java基础。

2.1 单接口单实现类

顾名思义,调用类调用接口的方法,且该方法只被一个实现类实现

① 创建CalledInterface接口

在里边写一个抽象方法

public interface CalledInterface {

    String getString();

}

② 使Called类实现该接口

也重写了getString抽象方法

@Component
public class Called implements CalledInterface{

    public Called(){
        System.out.println("该类被创建成功");
    }

    @Override
    public String getString() {
        return "getString 方法被调用";
    }
}

③ Call类注入该接口并作为控制层

以@Autowired为例

@RestController
public class Call {

    @Autowired
    private CalledInterface calledInterface;

    @RequestMapping("/call")
    public String call() {
        return calledInterface.getString();
    }
}

④ 执行项目启动类并访问该接口

输出成功,说明注入成功。

2.2 单接口多实现类

如果该接口有多个实现类呢,该如何处理?

首先增加另一个实现类试试:

@Component
public class CalledAnother implements CalledInterface{

    @Override
    public String getString() {
        return "CalledAnother 的 getString 方法被调用";
    }
}

然后执行启动类,可以看到项目报错了👇,说明系统不知道该调用哪个实现类的getString()方法。

主要有以下几种解决方法:

  • @Qualifier("类名"):@Autowired + @Qualifier("类名") 指定具体实现类(用在控制层)

  • @Resource(name = "类名"):这也可以实现(用在控制层)

  • @Primary:表示该实现类是主实现类,默认使用该类方法。(用在实现类)

而且可以使用 @Component("自定义类名") 和 @Service("自定义类名") 在实现类上自定义类名。

这里以@Resource(name = "类名")和@Service("自定义类名")为例:

① Called类使用@Service("自定义类名")

@Service("自定义类名")
public class Called implements CalledInterface{

    public Called(){
        System.out.println("该类被创建成功");
    }

    @Override
    public String getString() {
        return "Called 的 getString 方法被调用";
    }
}

② Call类使用@Resource(name = "类名")

@RestController
public class Call {

    @Resource(name = "自定义类名")
    private CalledInterface calledInterface;

    @RequestMapping("/call")
    public String call() {
        return calledInterface.getString();
    }

}

③ 执行项目启动类并访问该接口

说明指定具体实现类成功,其实还有好几种搭配方式,感兴趣的小伙伴可以自己尝试一下~

参考文章

1.Spring IoC(控制反转) (biancheng.net)

2.控制反转与依赖注入_望天边星宿的博客-CSDN博客

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

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

相关文章

分享112个HTML艺术时尚模板,总有一款适合您

分享112个HTML艺术时尚模板&#xff0c;总有一款适合您 112个HTML艺术时尚模板下载链接&#xff1a;https://pan.baidu.com/s/1D3-mfPOud-f3vy9yLl-bmw?pwdfph2 提取码&#xff1a;fph2 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 时尚平面模特网站模板 潮…

Redis数据类型以及应用场景

目录1、 String&#xff08;字符串&#xff09;2、 Hash&#xff08;哈希&#xff09;3、 List&#xff08;列表&#xff09;4、 Set&#xff08;集合&#xff09;5、 sorted set&#xff08;有序集合ZSet&#xff09;字符串&#xff08;String&#xff09;、哈希表&#xff08…

40/365 javascript 严格检查模式 字符串

1.严格检查模式 因为js语法的随意性&#xff0c;可以直接使用变量&#xff08;没有声明&#xff09;&#xff0c;也不会报错。 <script>n 5;</script> 但这样会造成很多问题&#xff0c;一是变量不声明就使用&#xff0c;二是这样使用的变量会是全局变量&#x…

Python数据容器、list列表、tuple元组、str字符串、数据容器(序列)切片、set集合、dict字典

数据来源 01 数据容器 为什么学习数据容器 数据容器 总结 02 列表 1&#xff09;列表定义 为什么需要列表 列表的定义语法 列表的定义方式 演示 """ 演示数据容器之:list列表 语法:[元素,元素,......] """ # 定义一个列表list my_list …

从零开始 verilog 以太网交换机(三)MAC发送控制器的设计与实现

从零开始 verilog 以太网交换机&#xff08;三&#xff09;MAC发送控制器的设计与实现 &#x1f508;声明&#xff1a; &#x1f603;博主主页&#xff1a;王_嘻嘻的CSDN主页 &#x1f9e8; 从零开始 verilog 以太网交换机系列专栏&#xff1a;点击这里 &#x1f511;未经作者允…

数据结构概述

逻辑结构 顺序存储 随机访问是可以通过下标取到任意一个元素&#xff0c;即数组的起始位置下标 链式存储 链式存储是不连续的&#xff0c;比如A只保留了当前的指针&#xff0c;那么怎么访问到B和C呢 每个元素不仅存储自己的值还使用额外的空间存储指针指向下一个元素的地址&a…

【python】英雄联盟电竞观赛引擎 掉落提示 CapsuleFarmerEvolved 「Webhook」「钉钉」

介绍 本项目链接 Github本项目链接 Gitee本项目链接 最近在github上发现一个可以用来自动帮你挂英雄联盟(除国服)电竞引擎(可以开出头像和表情)的项目,CapsuleFarmerEvolved,github原项目链接简单来说就是本来是通过看比赛获取奖励的,它帮助你进行观看. 对这个活动有兴趣的话…

3|物联网控制|计算机控制-刘川来胡乃平版|第1章:绪论|青岛科技大学课堂笔记|U1 ppt

目录绪论&#xff08;2学时&#xff09;常用仪表设备&#xff08;3学时&#xff09;计算机总线技术&#xff08;4学时&#xff09;过程通道与人机接口&#xff08;6学时&#xff09;数据处理与控制策略&#xff08;6学时&#xff09;网络与通讯技术&#xff08;3学时&#xff0…

sonarqube 生成pdf报错

sonar 生成report pdf报错&#xff0c;需要先配置username,password, Administration->PDF Report-> Password & Username https://gitee.com/zzulj/sonar-pdf-plugin sonar-pdf-plugin sonar-pdfreport-plugin-4.0.1.jar Installation 下载对应的版本&#xff…

Day894.加锁规则的一些问题 -MySQL实战

加锁规则的一些问题 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于加锁规则的一些问题的内容。 加锁规则&#xff0c;这个规则中&#xff0c;包含了两个“原则”、两个“优化”和一个“bug”&#xff1a; 原则 1&#xff1a;加锁的基本单位是 next-key lock。nex…

stable-diffusion-webui 安装使用

文章目录1.github 下载&#xff0c;按教程运行2.安装python 忘记勾选加入环境变量&#xff0c;自行加入&#xff08;重启生效&#xff09;3.环境变量添加后&#xff0c;清理tmp &#xff0c;venv重新运行4.运行报错&#xff0c;无法升级pip&#xff0c;无法下载包&#xff0c;5…

如何将Python打包后的exe还原成.py?

将python打包好的exe解压为py文件&#xff0c;步骤如下&#xff1a;下载pyinstxtractor.py文件下载地址&#xff1a;https://nchc.dl.sourceforge.net/project/pyinstallerextractor/dist/pyinstxtractor.py并将pyinstxtractor.py放到和exe相同的目录文件下打开命令控制台cd 进…

No.182# 技术管理之管理任务管理

引言继前文梳理「团队建设」与「管理规划」后&#xff0c;本文梳理下技术管理的另外一块「任务管理」。走查任务管理的主要内容&#xff1a;主要内容提点任务目标量化任务的优先级拉通形成共识团队梯队建设任务进度跟踪任务完成复盘一、主要内容提点二、任务目标量化任务管理&a…

QT mp3音乐播放器实现框架,Qt鼠标事件,网络编程,QSqlite,Json解析,HTTP请求等

QT mp3音乐播放器实现框架&#xff0c;Qt鼠标事件&#xff0c;网络编程&#xff0c;QSqlite,Json解析&#xff0c;HTTP请求等框架搭建UI设计mp3.hmp3.cpp隐藏窗口标题 最大化 最小化 关闭框架搭建 .pro添加 # 网络 添加多媒体 数据库 QT network multimedia sql添加头…

C进阶:5.动态内存管理

目录 1.为什么存在动态内存分配 2.动态内存函数的介绍 2.1 malloc 和 free 2.2 calloc malloc 与 calloc的区别&#xff1a; 2.3 realloc 3.常见的动态内存错误 3.1对NULL指针的解引用操作 3.2对动态开辟空间的越界访问 3.3对非动态开辟的内存使用free释放 3.4使用f…

帮助指令 man ,help及文档常用管理指令

帮助指令 man&#xff0c;help 1. man 当我们想要了解某个命令如何使用&#xff0c;及选项的含义是什么以及配置文件的帮助信息时&#xff0c;可以使用 man [命令或配置文件]&#xff0c;这样便可以获得到帮助提示信息了。 语法格式&#xff1a;man [命令或者配置文件] 比如…

[SSD科普之2] SATA、mSATA、M.2、M.2(NVMe)、PCIE固态硬盘接口详解

固态硬盘概念固态驱动器&#xff08;Solid State Drive&#xff09;&#xff0c;俗称固态硬盘&#xff0c;固态硬盘是用固态电子存储芯片阵列而制成的硬盘&#xff0c;因为台湾英语里把固体电容称之为Solid而得名。SSD由控制单元和存储单元&#xff08;FLASH芯片、DRAM芯片&…

最全280个上市公司数字化转型指标(2010-2021年)

基于年报测度数字化的论文在中文顶刊已有有趣的研究发表&#xff0c;从深交所、上交所下载2010-2021年上市公司年报&#xff0c;提取MD&A部分&#xff0c;基于《管理世界》、《经济研究》等期刊论文构建企业数字化词典&#xff08;详细参考见后文&#xff09;&#xff0c;将…

JavaScript系列之实现继承的几种方式

文章の目录一、借助父构造函数继承属性1、实现方式2、优点3、缺点二、原型链继承1、实现方式2、优点3、缺点三、组合继承四、ES6继承的实现方式参考写在最后一、借助父构造函数继承属性 1、实现方式 先定义一个父构造函数(this指向为window)&#xff1b;再定义一个子构造函数…

了解Nginx,这一篇就够了

了解Nginx&#xff0c;这一篇就够了1.Nginx应用场景2.Nginx相关概念正向代理和反向代理负载均衡动静分离3.Nginx配置文件解析全局块events块http块1.Nginx应用场景 HTTP服务器&#xff1a;Nginx本身也是一个静态资源的服务器&#xff0c;当只有静态资源的时候&#xff0c;就可…