[Spring] IoC 控制反转和DI依赖注入和Spring中的实现以及常见面试题

目录

1.  什么是Spring

2.什么是IoC容器

3.通过实例来深入了解IoC容器的作用

3.1造一量可以定义车辆轮胎尺寸的车出现的问题

3.2解决方法

3.3IoC优势

4.DI介绍

5.Spring中的IoC和DI的实现

5.1.存对象

5.1.2 类注解

5.1.3 方法注解

5.2取对像 (依赖注入)

5.2.1.属性注入

5.2.2.构造方法注入(Spring4.x推荐的)

5.2.3Setter注入(Sping 3.x推荐)

5.3三种注入方式的优缺点:

5.4@Autowired存在的问题

5.5常见面试题:


1.  什么是Spring

    Spring是一个开源框架,他让我们的开发更加简单,它支持广泛的应用场景,有着活跃而庞大的社区,这也是Spring能够长久不衰的原因.这个概念还是相对于比较抽象,我们用通俗易懂的话来讲,Spring是包含了众多工具方法的IoC容器 那么问题来了,容器是什么.什么是IoC容器

2.什么是IoC容器

容器是用来容纳某种物品的装置,IoC是Spring的核心思想,我们在类上面加入@RestControlle和@Controller注解,就是把这个对象交给Spring来管理,Spring框架在启动的时候就会加载该类,把对象交给Spring来管理就是IoC思想

IoC:  inversion of Con\rol(控制反转) 也就是说Spring是一个"控制反转容器"

那么什么是控制反转呢?也就是控制劝的反转.即获取对象的过程被反转了.

也就是说,当需要某个对象的时候,传统开发模式需要我们在类里面自己new对象,现在不需要我们自己去创建,而是把创建对象的任务交给容器,程序只需要依赖注入就可以了,这个容器被称为IoC容器,Spring是一个IoC容器,所以Spring有时候也被称为Spring容器.

控制反转是一种思想,在生活中也随处可见,比如,自动驾驶,在传统驾驶模式中,我们对于车的控制权是司机,但是在自动驾驶的时候,我们对于车辆的控制权就交给了自动驾驶系统.这也是一种控制反转

3.通过实例来深入了解IoC容器的作用

3.1造一量可以定义车辆轮胎尺寸的车出现的问题

我们想造一辆车,但是造车的时候,需要车身,造车身又需要底盘,底盘需要轮胎,我们当我造一辆车的时候,可以这样造:

public class Car {private  Framework framework; //我们在创建车的时候需要一个车身 这时候还需要一个车身类public Car(){framework = new Framework();System.out.println("Car init....");}public void run(){System.out.println("Car run ....");}
}
// 车身
public class Framework {private Bottom bottom;public Framework(){bottom = new Bottom();System.out.println("Framework init...");}
}
//底盘
public class Bottom {private Tire tire; //轮胎public Bottom(){System.out.println("Bottom init ...");}
}
//轮胎
public class Tire {int size; //轮胎的尺寸public Tire(){System.out.println("车胎的尺寸是");}
}

我们没写轮胎的尺寸的时候,相安无事,看起来很好,但是如果我们在轮胎的构造方法中加入它的尺寸.

就会出问题了,我们要想在造车的时候就传入轮胎的大小,就得把这一系列的代码构造方法全部改了,每一个都得加入int类型的size参数,这样无异于是很麻烦的.

那么有没有一种简单一些的办法可以让我们优化这些步骤呢?

3.2解决方法

我们尝试换一种方法,我们先设计汽车的大概样子,然后根据汽车来设计车身,在根据车身来设计地盘,在根据底盘来设计轮胎.

package com.example.demo.Car;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 ....");}public static void main(String[] args) {Tire tire = new Tire(14);Bottom bottom = new Bottom(tire);Framework framework1 = new Framework(bottom);Car car = new Car(framework1);car.run(); 
// 我们先造一个轮胎,然后轮胎指定了尺寸,
//把轮胎给底盘,底盘给车身,车身给车 这样我们如果想改车胎的参数,
//只需要改车胎的构造方法就行了,不需要把其它的都一起改}
}
// 车身
public class Framework {private Bottom bottom; //底盘public Framework(Bottom bottom){this.bottom = bottom;System.out.println("Framework init...");}
}
//底盘
public class Bottom {private Tire tire; //轮胎public Bottom(Tire tire){this.tire = tire;System.out.println("Bottom init ...");}
}
//轮胎
public class Tire {int size; //轮胎的尺寸public Tire(int size){System.out.println("车胎的尺寸是"+size);}
}

3.3IoC优势

传统的代码对象创建的顺序是 car-framework - bottom - tire

改进之后解耦代码的对象创建顺序是 tire - bottom - framework - car

  我们发现了⼀个规律,通⽤程序的实现代码,类的创建顺序是反的,传统代码是Car控制并创建了
   Framework,Framework创建并创建了Bottom,依次往下,⽽改进之后的控制权发⽣的反转,不再
是使⽤⽅对象创建并控制依赖对象了,⽽是把依赖对象注⼊将当前对象中,依赖对象的控制权不再由
当前类控制了.
 这样的话,即使依赖类发⽣任何改变,当前类都是不受影响的,这就是典型的控制反转,也就是IoC的实现思想。
这样IoC容器有以下好处

1.资源不由资源双方管理,而是不使用资源的第三方来进行管理,资源集中管理,实现了资源的可配置和易管理

2 降低了使用资源双方的依赖程度,也就是我们常说的解耦合.
 

4.DI介绍

上面学习了IoC,那么什么是DI呢? DI:Dependency Injection(依赖注⼊)

容器在运行阶段,动态的为应用程序提供运行的时候所依赖的资源,称为依赖注入.

程序运行的时候,需要哪个资源,此时容器就提供这个资源.  依赖注入和控制反转是从不同的角度来描述同一件事,通过引入IoC容器,利用依赖关系注入的方式,实现对象间的解耦合.

IoC是一种思想,也就是一种指导原则,而DI就是具体的实现,也就是说DI是IoC是一种实现

5.Spring中的IoC和DI的实现

既然是容器,那么肯定有存和取,Spring针对这两种操作都有自己的实现,下面我们来介绍一下在spring中存放对象和取对象这两种操作分别应该怎么用

5.1.存对象

共有两种注解类型可以实现:

5.1.2 类注解

@Controller (控制器存储) 

@Controller
public class TestController {public void func(){System.out.println("TestController...");}}

该类注解存放的是控制器对象,可以和前端访问或者交互到

那么Spring把这个对象存到哪里了呢? 我们可以在Spring给的main函数中验证出来

@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {//Spring上下文 存放的是Spring容器管理的对象ApplicationContext context = SpringApplication.run(DemoApplication.class, args);//通过类名和类型来找到这个对象TestController controller = context.getBean("testController", TestController.class);//执行对象中的方法controller.func();}}

@Serivce (服务存储) 存储的是业务逻辑相关的对象

@Repository 仓库存储 存储数据相关的 也称为吃就吃

@Component (组件存储) 其它几个类存储注解都继承自这个

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

其实这些注解⾥⾯都有⼀个注解 @Component ,说明它们本⾝就是属于 @Component 的"⼦类".
@Component 是⼀个元注解,也就是说可以注解其他类注解,如 @Controller , @Service ,
@Repository 等.这些注解被称为 @Component 的衍⽣注解.

5.1.3 方法注解

类注解固然可以用,但是存在两个问题:

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

2.一个类需要多个对象

我们可以使用我们的@Bean 方法注解 在Spring中 方法注解要配合我们的类注解才能存储到Spring容器中,如下:

@Component
public class BeanConfig {@Beanpublic User user1() {User user = new User();user.setName("zhangsan");user.setAge(18);return user;}@Beanpublic User user2() {User user = new User();user.setName("zhangsan");user.setAge(18);return user;}
}

上述代码中,我们定义了多个对象.那么这些对象我们又该怎么去取呢?

我们尝试获取一下

public static void main(String[] args) {//Spring上下文 存放的是Spring容器管理的对象ApplicationContext context = SpringApplication.run(DemoApplication.class, args);//通过类名和类型来找到这个对象User user = context.getBean(User.class);//执行对象中的方法System.out.println(user);}

运行以后发现代码报错了.

我们可以根据名字来获取到对象

public static void main(String[] args) {//Spring上下文 存放的是Spring容器管理的对象ApplicationContext context = SpringApplication.run(DemoApplication.class, args);//通过类名和类型来找到这个对象User user = context.getBean("user1",User.class);//执行对象中的方法System.out.println(user);}


我们还可以通过@Bean注解重命名对象 

5.2取对像 (依赖注入)

依赖注入是一个过程,是在IoC容器创建Bean时,去提供运行的时候所需要以来的资源,而这个资源就是对象.我们可以提供@Autowried这个注解来完成依赖注入这个操作

关于依赖注入,Spring也给我们提供了三种方法,

1. 属性注⼊(Field Injection)
2. 构造⽅法注⼊(Constructor Injection) 
3. Setter注⼊(Setter Injection) 

5.2.1.属性注入

我们可以举个例子来说明一下:

@Controller
public class TestController {@Autowiredprivate UserService userService;public void func(){userService.func();}
}
@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {//Spring上下文 存放的是Spring容器管理的对象ApplicationContext context = SpringApplication.run(DemoApplication.class, args);//通过类名和类型来找到这个对象TestController testController = context.getBean(TestController.class);//执行对象中的方法testController.func();}}

可以看到我们通过了依赖注入,拿到了对象,并且把它的方法使用了出来.

5.2.2.构造方法注入(Spring4.x推荐的)

这种是在构造方法中实现注入的

如果只要一个构造方法 那么@Autowried可以省略,如果有多个就需要添加@Autowried来明确指定到底要使用哪个构造方法.

5.2.3Setter注入(Sping 3.x推荐)

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

  private UserService userService;@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}

5.3三种注入方式的优缺点:

1.属性注入:

优点:简洁,使用方便,

缺点:只能用于IoC容器,并且会出现NPE

不能注入一个fina修饰的属性

2.构造函数注入;
优点: 可以注入fina修饰的属性,

注入的对象不会被修改

通用性好,构造方法是JDK支持的,换了任何框架都支持

依赖对象在使用时就会被完全初始化,因为依赖是在类的构造方法中执行的,而构造方法是在类加载阶段就执行的方法

缺点:注入多个对象的时候,代码繁琐

3.Setter注入

优点:方便在类实例之后,重新对改对象进行配置或者注入

缺点:不能注入final修饰的属性.注入对象夸你汇编,因为setter方法可能会被多次调用,有被修改的风险

5.4@Autowired存在的问题

同一个类型存在多个bean时 @Autowired会存在问题

@Autowiredprivate User user;public void func(){System.out.println(user);}

会报这个错误,

那么我们该如何解决这个问题呢?

Spring给我们 提供了三种解决方案:

1.@Primary注解

使用该注解,指定默认的对象

@Component
public class BeanConfig{@Bean@Primarypublic User user1() {User user = new User();user.setName("zhangsan");user.setAge(18);return user;}@Beanpublic User user2() {User user = new User();user.setName("zhangsan");user.setAge(18);return user;}
}

重新运行一下:

2.@Qualifier注解

指定当前要注入的bean对象

 @Autowired@Qualifier("user2")private User user;public void func(){System.out.println(user);}

3.Resource注解,按照bean名称进行注入,通过name属性指定要注入bean的名称

 @Resource(name = "user2")private User user;public void func(){System.out.println(user);}

5.5常见面试题:

@Autowird与@Resource的区别

1.@Autowird是spring框架提供的注解,而@Resource是JDK提供的

2.@Autowird是按照类型注入,@Resource是按照bean名称注入.相比于@Autowired来说,@Resource支持更多的参数设置,入name的设置,根据名称获取bean

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

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

相关文章

FPGA高端项目:FPGA基于GS2971的SDI视频接收+HLS多路视频融合叠加,提供1套工程源码和技术支持

目录 1、前言免责声明 2、相关方案推荐本博已有的 SDI 编解码方案本方案的SDI接收转HDMI输出应用本方案的SDI接收图像缩放应用本方案的SDI接收纯verilog图像缩放纯verilog多路视频拼接应用本方案的SDI接收HLS图像缩放Video Mixer多路视频拼接应用本方案的SDI接收OSD动态字符叠加…

护眼台灯怎么选比较好?明基、爱德华、书客护眼台灯硬核PK测评

现在不管是学生党学习阅读,还是办公族加班工作,都离不开一盏光源舒适的台灯,然而如今的台灯市场水实在太深的,各种网红、劣质产品混杂在其中,这类台灯往往采用劣质电源,其电源品质较差,导致输出…

VUE3 显示Echarts百度地图

本次实现最终效果 技术基础以及环境要求 vue3 echarts 百度地图API 要求1: VUE3 环境搭建:https://blog.csdn.net/LQ_001/article/details/136293795 要求2: VUE3 echatrs 环境搭建:https://blog.csdn.net/LQ_001/article/details/1363…

Ps:画笔工具

画笔工具 Brush Tool是 Photoshop 中最常用的工具,可广泛地用于绘画与修饰工作之中。 快捷键:B ◆ ◆ ◆ 常用操作方法与技巧 1、熟练掌握画笔工具的操作对于使用其他工具也非常有益,因为 Photoshop 中许多与笔刷相关的工具有类似的选项和操…

多层菜单的实现方案(含HierarchicalDataTemplate使用)

1、递归 下面是Winform的递归添加菜单栏数据,数据设置好父子id方便递归使用 在TreeView的控件窗口加载时,调用递归加载菜单 private void LoadTvMenu(){this.nodeList objService.GetAllMenu(); // 通过Service得到全部数据// 创建一个根节点this.t…

SQL中如何添加数据

SQL中如何添加数据 一、SQL中如何添加数据(方法汇总)二、SQL中如何添加数据(方法详细解说)1. 使用SQL脚本(推荐)1.1 在表中插入1.1.1 **第一种形式**1.1.2 **第二种形式**SQL INSERT INTO 语法示例SQL INSE…

【实战项目】网络编程:在Linux环境下基于opencv和socket的人脸识别系统--C++实现

🌞前言 这里我们会实现一个项目:在linux操作系统下基于OpenCV和Socket的人脸识别系统。 目录 🌞前言 🌞一、项目介绍 🌞二、项目分工 🌞三、项目难题 🌞四、实现细节 🌼4.1 关…

读算法的陷阱:超级平台、算法垄断与场景欺骗笔记06_共谋(下)

1. 博弈论 1.1. 当市场竞争对手之间普遍存在着误解和不信任情绪时,从长远来看,他们一半时间是在合作,另一半时间则是在背叛承诺 1.2. 当一方越了解对手,或者说可以更好地掌握对方的战略性行为时,他才可能找到展开合作…

软件设计不是CRUD(14):低耦合模块设计理论——行为抽象与设计模式(上)

是不是看到“设计模式”四个字,各位读者就觉得后续内容要开始讲一些假大空的内容了?各位读者是不是有这样的感受,就是单纯讲设计模式的内容,网络上能找到很多资料,但是看过这些资料后读者很难将设计模式运用到实际的工作中。甚至出现了一种声音:设计模式是没有用的,应用…

C++:vector底层剖析

文章目录 前言成员变量成员函数vector ()size_t size()size_t capacity()iterator begin()和const_iterator begin()constiterator end()和const_iterator end()const~vector()void push_back(const&T val)vector<T>(const vector<T>& v)vector<T>&a…

前端解决跨域问题( 6种方法 )

本专栏是汇集了一些HTML常常被遗忘的知识&#xff0c;这里算是温故而知新&#xff0c;往往这些零碎的知识点&#xff0c;在你开发中能起到炸惊效果。我们每个人都没有过目不忘&#xff0c;过久不忘的本事&#xff0c;就让这一点点知识慢慢渗透你的脑海。 本专栏的风格是力求简洁…

美团2025春招第一次笔试题

第四题 题目描述 塔子哥拿到了一个大小为的数组&#xff0c;她希望删除一个区间后&#xff0c;使得剩余所有元素的乘积未尾至少有k个0。塔子哥想知道&#xff0c;一共有多少种不同的删除方案? 输入描述 第一行输入两个正整数 n,k 第二行输入n个正整数 a_i&#xff0c;代表…

ARM TrustZone技术解析:构建嵌入式系统的安全扩展基石

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法|MySQL| ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-dSk2aQ85ZR0zxnyI {font-family:"trebuchet ms",verdana,arial,sans-serif;f…

【机器学习】进阶学习:详细解析Sklearn中的MinMaxScaler---原理、应用、源码与注意事项

【机器学习】进阶学习&#xff1a;详细解析Sklearn中的MinMaxScaler—原理、应用、源码与注意事项 这篇文章的质量分达到了97分&#xff0c;虽然满分是100分&#xff0c;但已经相当接近完美了。请您耐心阅读&#xff0c;我相信您一定能从中获得不少宝贵的收获和启发~ &#x1f…

free pascal 调用 C#程序读 Freeplane.mm文件,生成测试用例.csv文件

C# 请参阅&#xff1a;C# 用 System.Xml 读 Freeplane.mm文件&#xff0c;生成测试用例.csv文件 Freeplane 是一款基于 Java 的开源软件&#xff0c;继承 Freemind 的思维导图工具软件&#xff0c;它扩展了知识管理功能&#xff0c;在 Freemind 上增加了一些额外的功能&#x…

hadoop报错:HADOOP_HOME and hadoop.home.dir are unset. 解决方法

参考&#xff1a;https://blog.csdn.net/weixin_45735242/article/details/120579387 解决方法 1.下载apache-hadoop-3.1.0-winutils-master 官网下载地址&#xff1a; https://github.com/s911415/apache-hadoop-3.1.0-winutils win配置系统环境&#xff1a; 然后重启idea…

一文了解原型和原型链

本文重点概念&#xff1a; 1、所有的对象都是new一个函数创建的 2、所有的函数都有一个属性prototype&#xff0c;称为函数原型 3、函数原型得到的这个对象都有一个属性constructor,指向该函数 4、所有的对象都有一个属性&#xff1a;隐式原型__proto__&#xff0c;隐式原型…

机器学习,剪刀,石头,布

计算机视觉:剪刀,石头,步 TensorFlow AI人工智能及Machine Learning训练图集的下载建立分类模型并用图像进行训练检验模型总结当前AI Machine Learning 异常火爆,希望在MCU上使用机器学习,做图像识别的工作。看到一个剪刀,石头,步的学习程序,给大家分享一下。 TensorFl…

Buran勒索病毒通过Microsoft Excel Web查询文件进行传播

Buran勒索病毒首次出现在2019年5月&#xff0c;是一款新型的基于RaaS模式进行传播的新型勒索病毒&#xff0c;在一个著名的俄罗斯论坛中进行销售&#xff0c;与其他基于RaaS勒索病毒(如GandCrab)获得30%-40%的收入不同&#xff0c;Buran勒索病毒的作者仅占感染产生的25%的收入,…

AI创造的壁纸,每一幅都是视觉盛宴!

1、方小童在线工具集 网址&#xff1a; 方小童 该网站是一款在线工具集合的网站&#xff0c;目前包含PDF文件在线转换、随机生成美女图片、精美壁纸、电子书搜索等功能&#xff0c;喜欢的可以赶紧去试试&#xff01;