【Spring面试题】IOC控制反转和DI依赖注入(详解)

IOC

Inversion of Control

控制反转,是一种面向对象的思想。

控制反转就是把创建和管理 bean 的过程转移给了第三方。而这个第三方,就是 Spring IoC Container,对于 IoC 来说,最重要的就是容器。

通俗点讲,因为项目中每次创建对象是很麻烦的,所以我们使用 Spring IoC 容器来管理这些对象,需要的时候你就直接用,不用管它是怎么来的、什么时候要销毁,只管用就好了。

IOC思想

首先想说说IoC(Inversion of Control,控制反转)。这是spring的核心,贯穿始终。所谓IoC,对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的关系。这是什么意思呢,举个简单的例子,我们是如何找女朋友的?常见的情况是,我们到处去看哪里有长得漂亮身材又好的mm,然后打听她们的兴趣爱好、qq号、电话号、ip号、iq号………,想办法认识她们,投其所好送其所要,然后嘿嘿……这个过程是复杂深奥的,我们必须自己设计和面对每个环节。传统的程序开发也是如此,在一个对象中,如果要使用另外的对象,就必须得到它(自己new一个,或者从JNDI中查询一个),使用完之后还要将对象销毁(比如Connection等),对象始终会和其他的接口或类藕合起来。

  那么IoC是如何做的呢?有点像通过婚介找女朋友,在我和女朋友之间引入了一个第三者:婚姻介绍所。婚介管理了很多男男女女的资料,我可以向婚介提出一个列表,告诉它我想找个什么样的女朋友,比如长得像李嘉欣,身材像林熙雷,唱歌像周杰伦,速度像卡洛斯,技术像齐达内之类的,然后婚介就会按照我们的要求,提供一个mm,我们只需要去和她谈恋爱、结婚就行了。简单明了,如果婚介给我们的人选不符合要求,我们就会抛出异常。整个过程不再由我自己控制,而是有婚介这样一个类似容器的机构来控制。Spring所倡导的开发方式就是如此,所有的类都会在spring容器中登记,告诉spring你是个什么东西,你需要什么东西,然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。

IOC代码层面去理解

先看下面几种管理对象的方式

原始方式:

如果不用IOC,我们自己管理对象,通常我们创建A类,创建B类,然后在A类调用B类的某个方法。

缺点:A和B耦合度太高了,你改了B,你也得改A,不好维护。

 

工厂模式:

建立一个工厂类,A类调用工厂类,工厂类调用B类,这样你修改了B,不需要修改A,降低了耦合度。

 

IOC:

实现方式:IOC通过依赖注入来实现,依赖注入的关键是IOC容器SpringContainer,IOC容器的本质也是一个工厂。

 

在执行SpringBoot的run方法之后,会自动创建Spring容器,会自动扫描某些包下的某些bean。 

Spring容器、bean?

Spring容器也叫做IOC容器,本质上就是一个工厂,它不但能管理Bean,还能管理Bean的生命周期、作用域

Bean是Spring容器管理的对象,可以是任何一个java类的实例,例如数据库连接、业务逻辑类、控制器等。

哪些类会被注册到Spring容器?

@ComponentScan,该注解告诉Spring扫描那些包路径下的类,然后判断如果类使用了@Component,@Controller, @Service...等注解,就注入到Spring容器中

Spring容器如何配置第三方的Bean?

Spring容器管理自己写的Bean,你可以加注解来注册到容器里,但是第三方的Bean你如何装配?第三方的类,人家代码是在jar包里面的,你不能轻易改别人的代码,所以不能通过加注解的方式注入。

解决方法:通过配置文件来解决。

配置类,你加一个@Configuration注解,这样这个类就是配置类了。

DI依赖注入? 

DI思想

  IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的。比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了 spring我们就只需要告诉spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。在系统运行时,spring会在适当的时候制造一个Connection,然后像打针一样,注射到A当中,这样就完成了对各个对象之间关系的控制。A需要依赖 Connection才能正常运行,而这个Connection是由spring注入到A中的,依赖注入的名字就这么来的。那么DI是如何实现的呢? Java 1.3之后一个重要特征是反射(reflection),它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,spring就是通过反射来实现注入的。

  理解了IoC和DI的概念后,一切都将变得简单明了,剩下的工作只是在spring的框架中堆积木而已。

@Autowired实现

一旦你通过@Autowired注解将某个类或成员变量注入到你的类中,你就可以在你的代码中使用这个实例,调用它的方法或访问它的属性。

@Autowired会告诉Spring容器尝试为被注解的类或成员变量自动注入合适的Bean,以满足它们的依赖关系。

当你使用@Autowired时,Spring容器会在应用程序启动时扫描你的类,并尝试查找匹配的Bean,然后自动将它们注入到被注解的类或成员变量中。这样,你就不需要手动实例化和管理这些Bean,Spring容器会为你完成这些任务,从而使你的应用程序更加易于维护和扩展。

大白话来说就是:

你用@Autowired这个注解,就能直接从Spring容器中获取对应类的实例,就可以不用new的方式来创建Spring容器管理的Bean实例。

例如:

假设你有一个服务类MyService,你可以在另一个类中使用@Autowired注解将它注入进来,然后调用MyService的方法:

@Service
public class MyService {public void doSomething() {// 执行某些操作}
}@Controller
public class MyController {@Autowiredprivate MyService myService;public void handleRequest() {// 调用MyService的方法myService.doSomething();}
}

在这个示例中,MyService被注入为MyController的私有成员变量myService。Spring容器会自动将MyService的实例注入到myService成员变量中,然后你可以在handleRequest方法中使用myService来调用MyService的方法。

依赖注入获取Bean的好处:

解耦和可维护性:

直接使用new创建Bean会导致你的代码与具体的Bean实现紧密耦合,降低了代码的可维护性和灵活性。如果将Bean的创建过程放在代码中,当需要更改Bean实现时,你需要修改所有使用new创建Bean的地方,而使用依赖注入可以让你在不修改代码的情况下轻松切换实现。

单一职责原则:

使用new来创建Bean实例将责任混杂在一个类中,可能违反了单一职责原则。Spring的IoC容器负责管理Bean的创建和生命周期,这使得你的类可以专注于其核心职责,而不必关心如何创建依赖的Bean。

依赖注入的好处:

通过依赖注入,你可以在类的外部配置Bean的依赖关系,而不是硬编码在类内部。这样,你可以在不修改代码的情况下配置不同的Bean实现,以满足不同的需求或环境。

测试和模拟:

当你直接使用new创建Bean实例时,很难进行单元测试,因为你无法轻松地替换Bean的实现。使用依赖注入可以方便地使用模拟对象或替代实现进行单元测试。

Spring容器的管理:

Spring容器负责管理Bean的生命周期、作用域和依赖关系。使用容器管理Bean可以确保它们按照预期方式创建和销毁,以及在需要时进行依赖注入

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

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

相关文章

Xubuntu16.04系统中解决无法识别exFAT格式的U盘

问题描述 将exFAT格式的U盘插入到Xubuntu16.04系统中,发现系统可以识别到此U盘,但是打不开,查询后发现需要安装exfat-utils库才行。 解决方案: 1.设备有网络的情况下 apt-get install exfat-utils直接安装exfat-utils库即可 2.设备…

ZigBee案例笔记 -- RFID卡片读写(模拟饭卡)

RFID模拟饭卡应用 RFID(射频识别技术)RFID通讯协议RFID发展历史RFID操作流程说明RFID卡片读写流程RFID寻卡RFID防碰撞RFID选卡RFID卡密验证RFID读卡RFID写卡读写数据流程 RFID饭卡模拟案例驱动代码串口协议饭卡操作案例结果优化建议 RFID(射频…

C语言入门 Day_12 一维数组

目录 前言 1.创建一维数组 2.使用一维数组 3.易错点 4.思维导图 前言 存储一个数据的时候我们可以使用变量, 比如这里我们定义一个记录语文考试分数的变量chinese_score,并给它赋值一个浮点数(float)。 float chinese_scoe…

详细介绍如何基于ESP32实现低功耗的电子纸天气显示器--附完整源码

实现界面展示 这是一款天气显示器,由支持 wifi 的 ESP32 微控制器和 7.5 英寸电子纸(又名电子墨水)显示器供电。当前和预测的天气数据是从 OpenWeatherMap API 获取的。传感器为显示屏提供准确的室内温度和湿度。 该项目在睡眠时消耗约 14μA,在约 10 秒的清醒期…

GitHub打不开解决方法——授人以渔

打不开GitHub的原因之一,DNS地址解析到了无法访问的ip。(为什么无法访问?) 1、打开GitHub看是哪个域名无法访问,F12一下 2、DNS解析看对应的域名目前哪个IP可以访问 DNS解析的网址: (1&#x…

上海的正西边有哪些城市

背景 上海一路向西,来一趟拉萨之行,那么上海出现,所经过的那么多城市,哪些是在上海的正西边呢? 画一幅地图 基于这个背景需求,我们需要拿来一幅地图,一看便知。下面的python代码生成了一幅地…

Ubuntu升级Cmake、gcc、g++

背景 最近要安装llvm,我选择的是从源码安装,所以要使用Cmake进行构建项目。但是服务器上的Cmake、gcc、g的版本都太低了,不符合要求,所以要对此进行升级。在本博客中采用的升级方法不一定是最好的方法(因为我也是参考…

跨数据中心Multi-Fabric解决方案:L2和L3网络的高效连接和扩展

云数据中心里,为什么需要DCI互通? 云化数据中心,网络资源通过虚拟化技术形成资源池,实现业务与物理网络解耦,通过网络虚拟化,物理网络资源可以被分成多个虚拟网络资源,从而提高网络资源的使用效…

操作系统的发展和分类

注意:每个阶段的主要优点都是解决了上个阶段的缺点 1.手工操作阶段 概括:一个用户在一段时间内独占全机,导致资源利用率极低,用户输入指令给机器,然后机器运行响应给用户。 2.批处理阶段 2.1单道批处理系统 优点&…

【LeetCode】85.最大矩形

题目 给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。 示例 1: 输入:matrix [["1","0","1","0","0"],["1&quo…

图解 STP

网络环路 现在我们的生活已经离不开网络,如果我家断网,我会抱怨这什么破网络,影响到我刷抖音、打游戏;如果公司断网,那老板估计会骂娘,因为会影响到公司正常运转,直接造成经济损失。网络通信中&…

基于Matlab利用IRM和RRTstar实现无人机路径规划(附上源码+数据+说明+报告+PPT)

无人机路径规划是无人机应用领域中的关键问题之一。本文提出了一种基于IRM(Informed RRTstar Method)和RRTstar(Rapidly-exploring Random Tree star)算法的无人机路径规划方法,并使用Matlab进行实现。该方法通过结合I…

设计模式行为型-状态模式

文章目录 简介状态模式基础定义状态接口或抽象类实现具体状态类 上下文类与状态转换上下文类的定义和作用状态转换及触发条件 状态模式的优势与适用性优点一:可维护的代码优点二:清晰的状态管理适用场景一:对象拥有多个状态适用场景二&#x…

【Unity】常见的角色移动旋转

在Unity 3D游戏引擎中,可以使用不同的方式对物体进行旋转。以下是几种常见的旋转方式: 欧拉角(Euler Angles):欧拉角是一种常用的旋转表示方法,通过绕物体的 X、Y 和 Z 轴的旋转角度来描述物体的旋转。在Un…

区块链技术与应用 - 学习笔记1【引言】

大家好,我是比特桃。本系列主要将我之前学习区块链技术时所做的笔记,进行统一的优化及整合。其中大量笔记源于视频课程:北京大学肖臻老师《区块链技术与应用》公开课。肖老师的课让我找回了求知若渴般的感觉,非常享受学习这门课的…

内存管理方式

内存管理 一、C/C内存分布1、内存空间的介绍2、示例题目3、示例题目图解 二、C语言动态内存管理方式1、代码2、介绍 三、C内存管理方式1、概念2、代码3、代码所代表的意义 四、new和delete操作自定义类型1、代码2、运行结果3、特点 五、operator new与operator delete函数1、概…

Go的数据结构-hashmap

开放寻址法和拉链法 runtime.hamp bucket的数据结构 bucket的指针指向这里 map初始化:make 和字面量 make初始化 新建一个hamp结尾体,计算大B,创建一个桶数组 字面量初始化 map的并发解决 sync.map

无涯教程-JavaScript - QUARTILE函数

QUARTILE函数取代了Excel 2010中的QUARTILE.INC函数。 描述 该函数返回数据集的四分位数。四分位数通常用于销售和调查数据中,以将人群分为几类。 语法 QUARTILE (array,quart)争论 Argument描述Required/OptionalArrayThe array or cell range of numeric values for whi…

怎么提取视频中的音乐保存到本地?其实方法很简单

当你想要使用视频中的音乐时,你可以考虑将它从视频中提取出来。这可以用于制作音频样本集,制作铃声或其他音频素材,或者向其他人展示视频的音乐部分而无需显示视频本身。如果你是一位音乐制作人员,你可能会需要一些特定类型的音效…

CP Autosar-Ethernet配置

文章目录 前言一、Eth层级结构介绍二、Autosar实践2.1 ETH Driver2.2 Eth InterfaceEth Interface Autosar配置2.3 TcpIp模块Eth TcpIp Autosar配置2.4 SoAdEth SoAd配置前言 因汽车E/E架构和功能的复杂度提升而带来的对车辆数据传输带宽提高和通讯方式改变(基于服务的通讯-S…