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

Spring依赖注入与反转控制到底是个啥?

目录

1. 引言

2. 管中窥豹

3.1 Spring 依赖注入

3.2  Bean 的依赖注入方式有两种

4. 总结 


1. 引言

        此文目的是用通俗易懂的语言讲清楚什么是依赖注入与反转控制,在看了大量的博客文章后归纳总结,便于后续巩固!我相信,大多数人像我一样,刚开始学习Spring框架的时候仅仅是在学习技术,记住如何做而非为何如此做。因此,本文结合生活例子与项目实际问题入手,讲清楚Spring入门的两个概念。其中,第二篇章管中窥豹需要具备Spring基础知识,你不用非常理解但至少你知道怎么写依赖注入。

2. 管中窥豹

        话说,有一天蟹老板想开个餐馆,可是开什么店好呢?他列出了几个选择,牛排店、蟹肉煲店、炸鸡店,火锅店,他非常纠结。于是海绵宝宝告诉他你可以春天卖牛排、夏天卖蟹肉堡、秋天换卖炸鸡,冬天卖火锅。于是,蟹老板接纳了海绵宝宝的意见。春天到了,蟹老板叫海绵宝宝开发了一套店内点餐系统,于是海绵宝宝定义了如下代码:

public interface Chef {public void cook(); // 厨师长做菜public void sing(); // 厨师长唱歌
}

并且从海底世界招聘到了张三厨师长,张三厨师长很擅长做牛排,尤其是黑椒牛排一绝,他也喜欢唱歌,因此海绵宝宝写下了如下代码:

public class ZhangChef implements Chef {String name;int age;public ZhangChef(String name, int age) {this.name = name;this.age = age;}@Overridepublic void cook() {System.out.println(name+"正在做黑椒牛排...");}@Overridepublic void sing() {System.out.println(name+"唱着伤不起...");}
}

最后,在我们的蟹老板的英明带领下,嘉年华顺利开店:

public class Restaurant {private String name;private String specialty;Restaurant(String name, String specialty) {this.name = name;this.specialty = specialty;}public void kitchen(){ZhangChef zhang = new ZhangChef("张三",26);System.out.println("我们的厨师长是:"+zhang.name+",今年高龄:"+zhang.age);zhang.cook(); //厨师做菜}}
运行结果>>>  我们的厨师长是:张三,今年高龄:26张三正在做黑椒牛排...

         这三个月过的很快,蟹老板也赚了很多钱,海绵宝宝更是成为了本店的CTO,大家其乐融融,一片安好。可是明天就到了夏天,餐厅更换业务,开始经营蟹肉煲,于是张三厨师长被毕业了,李四厨师长正好擅长蟹肉煲,我们的厨师长现在换成了李四。晚上十点钟,海绵宝宝正在加班加点改代码,他需要把整个系统的厨师长换成李四,这是他换好的第一个文件:

public class LiChef implements Chef {String name;int age;public LiChef(String name, int age) {this.name = name;this.age = age;}@Overridepublic void cook() {System.out.println(name+"正在做蟹肉煲...");}@Overridepublic void sing() {System.out.println(name+"唱着撒浪嘿呦...");}
}

        然后,他需要把整个系统所有方法的zhangChef换成LisiChef,海绵宝宝工作了一夜,第二天依旧没有改完,直到改了半个月后才把整个系统的Chef换完,于是海绵宝宝丢了CTO的职位,成为了普通打工仔程序员。海绵宝宝很不甘心,他辞去了工作,专心研究这个问题如何解决。他发现,Chef 类需要在 Restaurant 类中被实例化,他认为 Restaurant 过于依赖 Chef 了,这不是废话吗?餐厅当然依赖与厨师了,一瞬间他灵机一动说:这种依赖关系是不可避免的,这样做是过度耦合的,我需要给他们解耦!Chef 的控制权并不应该由餐厅掌控,而应该是需要的时候由第三方空降,于是他把Chef 变成了 Restaurant 类的一个变量,Restaurant 不具备实例化他的能力,而是由第三方实例化好后直接赋值给Chef变量,于是他改写成如下代码:

public class Restaurant {private String name;private String specialty;private Chef chef;#=====================================public void setChef(Chef chef) {this.chef = chef;} #=====================================Restaurant(String name, String specialty) {this.name = name;this.specialty = specialty;}public void kitchen(){ #======================chef = 第三方力量直接空投 ;#======================System.out.println("我们的厨师长是:"+chef.name+",今年高龄:"+chef.age);chef.cook(); //厨师做菜}
}

        如上面代码所示,第三方力量直接空投怎么实现呢?海绵宝宝思考了一夜,他想到了注射器,能不能像打针一样,把已经实例化好的Chef直接注射到 "chef = 第三方力量直接空投 ;"中的chef 呢?经过漫长的研究,海绵宝宝研发了一款框架,这种框架就是用来解决此问题,因为这是今年春天开始经历的困难,于是他把该框架命名成Spring。

3.1 Spring 依赖注入

        他感悟道:如果一个类A 的功能实现需要借助于类B,那么就称类B是类A的依赖,如果在类A的内部去实例化类B, 那么两者之间会出现较高的耦合,一旦类B出现了问题,类A也需要进行改造,如果这样的情况较多,每个 类之间都有很多依赖,那么就会出现牵一发而动全身的情况,程序会极难维护,并且很容易出现问题。要解决这个问题,就要把A类对B类的控制权抽离出来,交给一个第三方去做,把控制权反转给第三方,就称 作控制反转(IOC Inversion Of Control)。控制反转是一种思想,是能够解决问题的一种可能的结果, 而依赖注入(Dependency Injection)就是其最典型的实现方法。由第三方(我们称作IOC容器)来控制依赖,把他通过构造函数 、属性或者工厂模式 等方法,注入到类A内,这样就极大程度的对类A和类B 进行了解耦。

        上面 "chef = 第三方力量直接空投 ;" 写成:

    ApplicationContext applicationContext = newClassPathXmlApplicationContext("applicationContext.xml");Chef chef = (Chef) applicationContext.getBean("chef");
<bean id="chef" class="com.myjava.zhangChef"/>

        这一步还不是依赖注入,只是使用Spring的API实例化对象。因为有setChef 方法,我们可以配置Spring容器调用set方法进行注入,如下才是依赖注入,Spring会自动调用setChef方法给chef设置实例对象,因此不需要上面那一句“chef = 第三方力量直接空投”。真正的空投看不见!

<bean id="chef" class="com.myjava.LiChef"/>
<bean id="restaurant" class="com.myjava.Restaurant"><property name="chef" ref="chef"/>
</bean>

        如果A类需要使用B类,那么我们称为B是A的依赖,我们需要Spring容器(第三方)将依赖B的示例注射给A。因此,需要在Spring核心配置文件中声明控制权,将指定全限定名称的类的控制权(创建权)交给Spring管理,意味着我们可以通过Spring的getBean()实例化。如果类 chef 后期需要升级维护,我们只需要更改其中的代码或者指定其他的类全限定名称(class名称)。

3.2  Bean 的依赖注入方式有两种

①构造方法

​         创建有参构造

public class UserServiceImpl implements Userservice{private UserDao userDao;public UserServiceImpl(UserDao userDao){this.userDao = userDao;}
}

​         配置Spring容器调用有参构造时进行注入

<bean id="userDao" class="com.myjava.dao.impl.UserDaoImpl"/>
<bean id="userService" class="com.myjava.service.impl.UserServiceImpl">                     <constructor-arg name="userDao" ref="userDao"></constructor-arg>
</bean>

②set方法

​         在UserServiceImpl中添加setUserDao方法

public class UserServiceImpl implements UserService {private UserDao userDao;public void setUserDao(UserDao userDao) {this.userDao = userDao;  } @Override    public void save() {      userDao.save();}
}

​         配置Spring容器调用set方法进行注入

<bean id="userDao" class="com.myjava.dao.impl.UserDaoImpl"/>
<bean id="userService" class="com.myjava.service.impl.UserServiceImpl"><property name="userDao" ref="userDao"/>
</bean>

4. 总结 

        依赖注入是反转控制的一种实现方法,我个人认为依赖外置比依赖注入更好理解,当然我可能理解的不太深刻有错误。因为原来的程序是直接在A里面实例化B,如果B变了那将导致很多业务代码需要改,这种依赖关系又是无法消除的,只能减弱这种依赖。那么,可以考虑将依赖写到配置文件中,需要的时候注入即可,这里将依赖写到配置文件可以说是依赖外置,但是Spring在运行时是实例化对象然后通过Set或者构造方法将其注入到A类中,因此,这是一个相对的说法。从A类角度出发是外置,从Spring角度是注入。以上内容参考了知乎胡小国博主的文章,感谢!以上内容有错误希望指正!

相关文章:

Spring依赖注入与反转控制到底是个啥?

目录 1. 引言 2. 管中窥豹 3.1 Spring 依赖注入 3.2 Bean 的依赖注入方式有两种 4. 总结 1. 引言 此文目的是用通俗易懂的语言讲清楚什么是依赖注入与反转控制&#xff0c;在看了大量的博客文章后归纳总结&#xff0c;便于后续巩固&#xff01;我相信&#xff0c;大多数…...

Linux Shell脚本讲解

目录 Shell脚本基础 Shell脚本组成 Shell脚本工作方式 编写简单的Shell脚本 Shell脚本参数 Shell脚本接收参数 Shell脚本判断用户参数 文件测试与逻辑测试语句 整数测试比较语句 字符串比较语句 Shell流程控制 if条件判断语句 单分支 双分支 多分支 for循环语句…...

Linux:用户空间非法指针coredump简析

1. 前言 限于作者能力水平&#xff0c;本文可能存在谬误&#xff0c;因此而给读者带来的损失&#xff0c;作者不做任何承诺。 2. 背景 本文分析基于 ARM32 架构&#xff0c;Linux-4.14 内核代码。 3. 问题分析 3.1 测试范例 void main(void) {*(int *)0 8; }运行程序会 …...

带你玩转Jetson之Deepstream简明教程(四)DeepstreamApp如何使用以及用于工程验证。

1.DeepstreamApp是什么&#xff1f; 如果你安装完毕deepstream整体框架&#xff0c;会在你的系统执行目录内有可执行文件&#xff0c;文件名字是deepstream-app。这是一个可执行脚本文件&#xff0c;通过deepstream框架中的代码在安装的时候编译后install到系统根目录内。 此脚…...

快速搭建个人在线书库,随时随地畅享阅读!

前边我们利用NAS部署了个人的导航页、小说站、云笔记&#xff0c;今天&#xff0c;我们再看看怎么部署一个个人的在线书库。 相信很多朋友都在自己的电脑中收藏了大量的PDF、MOBI等格式的电子书籍&#xff0c;但是一旦换了一台设备&#xff0c;要么是无法翻阅&#xff0c;要么…...

电子纸墨水屏的现实应用场景

电子纸挺好个东西&#xff0c;大家都把注意力集中在商超场景 其实还有更多有趣的场景方案可用&#xff0c;价值也不小&#xff0c;比如&#xff1a; 一、仓库场景 通过亮灯拣选&#xff0c;提高仓库作业效率 二、仓库循环使用标签 做NFC类发卡式应用&#xff0c;替代传统纸…...

常量const、引用、指针的大杂烩

文章目录1 普通引用1.1 对普通值的普通引用1.2 对常量值的普通引用1.3 对普通指针的普通引用1.4 对常量指针的普通引用1.5 对指针常量的普通引用1.6 对指向常量的指针常量的普通引用2 常量引用2.1 对普通值的常量引用2.2 对常量值的常量引用2.3 对普通指针的常量引用2.4 对常量…...

宝塔搭建实战php开源likeadmin通用管理移动端uniapp源码(四)

大家好啊&#xff0c;我是测评君&#xff0c;欢迎来到web测评。 上一期给大家分享了pc端的部署方式&#xff0c;今天来给大家分享uniapp端在本地搭建&#xff0c;与打包发布到宝塔的方法。感兴趣的朋友可以自行下载学习。 技术架构 vscode node16 vue3 uniapp vite types…...

Hive的分区表与分桶表内部表外部表

文章目录1 Hive分区表1.1 Hive分区表的概念&#xff1f;1.1.1 分区表注意事项1.2 分区表物理存储结构1.3 分区表使用场景1.4 静态分区表是什么&#xff1f;1.4.1 静态分区表案例1.4.2 分区表练习一1.4.3 分区操作1.5 动态分区表是什么&#xff1f;1.5.1 动态态分区表案例&#…...

和数集团打造《神念无界:源起山海》,诠释链游领域创新与责任

首先&#xff0c;根据网上资料显示&#xff0c;一部《传奇》&#xff0c;二十年热血依旧。 《传奇》所缔造的成绩&#xff0c;承载的是多少人的青春回忆&#xff0c;《传奇》无疑已经在游戏史上写下了浓墨重彩的一笔。 相比《传奇》及背后的研发运营公司娱美德名声大噪&#x…...

小白入门模拟IC设计,如何快速学习?

众所周知&#xff0c;模拟电路很难学。以最普遍的晶体管来说&#xff0c;我们分析它的时候必须首先分析直流偏置&#xff0c;其次在分析交流输出电压。可以说&#xff0c;确定工作点就是一项相当麻烦的工作&#xff08;实际中来说&#xff09;&#xff0c;晶体管的参数多、参数…...

51单片机——中断系统之外部中断实验,小白讲解,相互学习

中断介绍 中断是为使单片机具有对外部或内部随机发生的事件实时处理而设置的&#xff0c;中断功能的存在&#xff0c;很大程度上提高了单片机处理外部或内部事件的能力。它也是单片机最重要的功能之一&#xff0c;是我们学些单片机必须要掌握的。 为了更容易的理解中断概念&…...

如何设计一个秒杀系统

秒杀系统要如何设计&#xff1f; 前言 高并发下如何设计秒杀系统&#xff1f;这是一个高频面试题。这个问题看似简单&#xff0c;但是里面的水很深&#xff0c;它考查的是高并发场景下&#xff0c;从前端到后端多方面的知识。 秒杀一般出现在商城的促销活动中&#xff0c;指定…...

厄瓜多尔公司注册方案

简介&#xff1a; 经济概况与商机 厄瓜多尔是世界上第74大国家&#xff0c;是南美西部国家&#xff0c;与哥伦比亚&#xff0c;秘鲁和太平洋接壤。厄瓜多尔地处世界中心&#xff0c;地理位置优越&#xff0c;地理位置优越-赤道线零纬度&#xff0c;使其成为通往太平洋的理想枢…...

安全渗透环境准备(工具下载)

数据来源 01 一些VM虚拟机的安装 攻击机kali&#xff1a; kali官网 渗透测试工具Kali Linux安装与使用 kali汉化 虚拟机网络建议设置成NAT模式&#xff0c;桥接有时不稳定。 靶机OWASP_Broken_Web_Apps&#xff1a; 迅雷下载 网盘下载 安装教程 开机之后需要登录&am…...

118.(leaflet篇)leaflet空间判断-点与geojson面图层的空间关系(turf实现)

听老人家说:多看美女会长寿 地图之家总目录(订阅之前建议先查看该博客) 文章末尾处提供保证可运行完整代码包,运行如有问题,可“私信”博主。 效果如下所示: 下面献上完整代码,代码重要位置会做相应解释 <!DOCTYPE html> <html>...

目标检测与目标跟踪算法技术汇总

现如今chatgpt的爆火&#xff0c;我也使用了一段时间&#xff0c;问了许多关于人工智能技术的问题&#xff0c;基本是它能够回答了大部分的原理的&#xff0c;至于其人工智能涉及到的算法以及网络&#xff0c;考虑到也没有图&#xff0c;可能在给出这类回答上&#xff0c;是不太…...

Linux 系统启动过程

过去几十年&#xff0c;公用事业行业发生了重大变化。能源需求的转变导致企业利润率的波动&#xff0c;但不是运营成本的波动。 许多公用事业公司通过后勤部门流程自动化来削减成本&#xff0c;比如招采流程自动化。 在招采活动中&#xff0c;人工招采会产生盲点。由于公共事业…...

【每日一题Day118】LC1124表现良好的最长时间段 | 前缀和+单调栈/哈希表

表现良好的最长时间段【LC1124】 给你一份工作时间表 hours&#xff0c;上面记录着某一位员工每天的工作小时数。 我们认为当员工一天中的工作小时数大于 8 小时的时候&#xff0c;那么这一天就是「劳累的一天」。 所谓「表现良好的时间段」&#xff0c;意味在这段时间内&#…...

vue使用nprogress(进度条)

目录 1.安装 2.引入 3.配置 4.使用 5.使用场景 6.改变颜色 1.安装 npm install --save nprogress2.引入 import NProgress from nprogress import nprogress/nprogress.css3.配置 NProgress.configure({easing: ease, // 动画方式&#xff0c;和css动画属性一样&#…...

@NotNull 、@NotBlank、@NotEmpty区别和使用

引言 今天在使用validation校验的时候&#xff0c;发现了使用校验不起作用&#xff0c;一时间有点摸不到头绪&#xff0c;就看了一下同事提交的代码&#xff0c;发现了问题在用NotNull用法&#xff0c;用的有些错误&#xff0c;所以在这里讲一下NotNull、NotBlank、NotEmpty区…...

Nacos——Nacos简介以及Nacos Server安装

资料来源&#xff1a;02-Nacos配置管理-什么是配置中心_哔哩哔哩_bilibili nacos记得下载2.x版本的&#xff0c;负责以后新建配置的时候会出现“发布错误&#xff0c;请检查参数是否正确”错误&#xff01;&#xff01;&#xff01;&#xff01; 目录 一、Nacos简介 1.1 四…...

Presto 文档和笔记

1. Presto Presto 官网 Presto 文档 2. 配置 3.1 node 配置 cat etc/node.properties # Generated by Apache Ambari. Fri Feb 10 14:52:10 2023node.data-dir/mnt/bmr/presto/data node.environmentproduction node.idbmr-master-4b7cbaa3.2 jvm 配置 cat etc/jvm.confi…...

大尺度衰落与小尺度衰落

一. 大尺度衰落 无线电磁波信号在收发天线长距离&#xff08;远大于传输波长&#xff09;或长时间范围发生的功率变化&#xff0c;称为大尺度衰落&#xff0c;一般可以用路径损耗模型来描述&#xff0c;路径损耗是由发射功率在空间中的辐射扩散造成的&#xff0c;根据功率传输…...

完美解决:重新安装VMware Tools灰色。以及共享文件夹的创建(centos8)

解决&#xff1a;重新安装VMware Tools灰色问题&#xff1a;重新安装VMware Tools灰色解决方案-挂载VMware中的linux.iso1. vmtools的linux.iso挂载及安装2. 共享文件夹的创建及配置问题&#xff1a;重新安装VMware Tools灰色 发现一个小问题&#xff0c;我的vm虚拟机安装后发…...

达梦数据库作业管理

一、基本功能 作业系统大致包含作业&#xff0c;警报&#xff0c;操作员三部分。 作业可运行DMPL/SQL脚本&#xff0c;定期备份数据库&#xff0c;检查等。可定时执行&#xff0c;也可通过警报触发执行&#xff0c;可产生警报通知用户状态。一个作业由多个步骤组成&#xff0c…...

数据结构-考研难点代码突破(C++实现树型查找-二叉搜索树(二叉排序树))

文章目录1.二叉搜索树基本操作二叉搜索树的效率分析2. C实现1.二叉搜索树基本操作 二叉排序树是具有下列特性的二叉树&#xff1a; 若左子树非空&#xff0c;则左子树上所有结点的值均小于根结点的值。若右子树非空&#xff0c;则右子树上所有结点的值均大于根结点的值。左、…...

emqx异常处理

启动异常 通过解压tar压缩包安装后通过 ./bin/emqx start 启动报错 WARNING: Default (insecure) Erlang cookie is in use. WARNING: Configure node.cookie in /opt/emqx/etc/emqx.conf or override from environment variable EMQX_NODE__COOKIE NOTE: Use the same config…...

Web前端:开始学习ReactJS需要知道什么?

毫无疑问&#xff0c;ReactJS是前端开发者中最著名的库之一&#xff0c;它的受欢迎程度与日俱增。用ReactJS构建的网站看起来非常棒&#xff0c;大多数开发新手都被它吸引住了。然而&#xff0c;许多新人和有经验的开发人员在没有首先了解先决条件的情况下&#xff0c;就直接用…...

卡诺图化简

1.相关概念 最小项&#xff1a;函数的某个乘积项包含了函数的全部变量&#xff08;原变量或反变量的形式&#xff09;&#xff0c;且每个变量仅出现一次&#xff0c;则这个乘积项为该函数的一个标准积项。 最小项中的原变量记为1&#xff0c;反变量记为0&#xff0c;当变量顺序…...

做什么网站能吸引流量/平台开发

【一、简介】 I2C总线&#xff08;Inter IC Bus&#xff09;是PHLIPS公司推出的一种串行总线标准&#xff0c;是具备多主机系统所需的包括总线裁决和高低速器件同步功能的高性能串行总线。I2C总线支持多主和主从&#xff08;常用&#xff09;两种工作方式。 在主从工作方式中&a…...

wordpress 置顶顺序/国际军事新闻最新消息

嵌入式芯片暨智能互联创新大赛为了加强全国高校学生在嵌入式芯片与系统设计应用领域的创新设计与工程实践能力&#xff0c;使学生能够全面掌握芯片设计或软硬适配系统优化、应用方案设计等不同技术层面的相关知识和技能&#xff0c;丰富和活跃校园创新创业学术氛围&#xff0c;…...

wordpress 获取当前位置/刷链接浏览量网站

[转载]App Store 申请经验 完整的IDP申请直到软件上架 (2011-06-07 16:10:43)转载原文标签&#xff1a; 转载原文地址&#xff1a;App Store 申请经验 完整的IDP申请直到软件上架销售流程作者&#xff1a;code第一&#xff1a;IDP的申请1.先在iPhone DevCenter上注册成为iphone…...

网站运行环境建设方案/杭州谷歌seo公司

我已经在我的项目中实现了一个Calendarview,我可以获取月份,月份和年份,但是我找不到任何获取星期几的方法,我的代码是这样的&#xff1a;view new CalendarView(this);setContentView(view);view.setOnDateChangeListener(new OnDateChangeListener() {Overridepublic void o…...

长沙建设银行招聘网站/哪个平台可以接推广任务

1.SVN基本介绍&#xff1a; 1.svn基本的概念 2.svn架构 3.svn下载与安装 4.svn搭建与基本操作 2.svn基本操作 1.操作1 2.操作2 3.冲突产生 4.冲突解决 3.SVN在IDEA下的基本使用 1.IDEA下svn配置与share project 2.IDEA下SVN基本使用 3.SVN目录结构及作用 4.SVN打分支及主干合并…...

傻瓜式网站源码/线上培训课程

一、ADO概述 ADO是Microsoft为最新和最强大的数据访问范例 OLE DB 而设计的&#xff0c;是一个便于使用的应用程序层接口。ADO 使您能够编写应用程序以通过 OLE. DB 提供者访问和操作数据库服务器中的数据。ADO 最主要的优点是易于使用、速度快、内存支出少和磁盘遗迹小。ADO 在…...