【JavaEE】深入理解Spring IoC与DI:从传统开发到依赖注入的转变

news2024/11/25 14:57:29

目录

      • IoC & DI ⼊⻔
        • 什么是Spring
        • 什么是容器
        • 什么是IoC
        • IoC介绍
          • 传统程序开发
          • 问题分析
          • 解决方案
          • IoC程序开发
          • IoC优势


IoC & DI ⼊⻔

IoC:Inversion of Control (控制反转)

DI:Dependency Injection

在前⾯我们学习了Spring Boot和Spring MVC的开发, 可以完成⼀些基本功能的开发了, 但是什么是Spring呢? Spring, Spring Boot 和SpringMVC⼜有什么关系呢?

我们先看什么是Spring

什么是Spring

通过前⾯的学习, 我们知道了Spring是⼀个开源框架, 他让我们的开发更加简单. 他⽀持⼴泛的应⽤场景, 有着活跃⽽庞⼤的社区, 这也是Spring能够⻓久不衰的原因.

但是这个概念相对来说, 还是⽐较抽象.

Spring两大核心思想:

  1. IoC
  2. AOP

我们⽤⼀句更具体的话来概括Spring, 那就是: Spring 是包含了众多⼯具⽅法的 IoC 容器

什么是容器?什么是 IoC 容器?接下来我们⼀起来看

什么是容器

容器是⽤来容纳某种物品的(基本)装置。

来⾃:百度百科

⽣活中的⽔杯, 垃圾桶, 冰箱等等这些都是容器.

我们想想,之前我们接触的容器有哪些?

  • List/Map -> 数据存储容器
  • Tomcat -> Web 容器

Spring容器,装的是 IoC 对象

什么是IoC

IoC 是Spring的核⼼思想, 也是常⻅的⾯试题, 那什么是IoC呢?

其实IoC我们在前⾯已经使⽤了, 我们在前⾯讲到, 在类上⾯添加 @RestController@Controller 注解, 就是把这个对象交给Spring管理, Spring 框架启动时就会加载该类. 把对象交给Spring管理, 就是IoC思想.

IoC: Inversion of Control (控制反转), 也就是说 Spring 是⼀个"控制反转"的容器.

什么是控制反转呢? 也就是控制权反转. 什么的控制权发⽣了反转? 获得依赖对象的过程被反转了,交给了Spring

也就是说, 当需要某个对象时, 传统开发模式中需要⾃⼰通过 new 创建对象, 现在不需要再进⾏创建, 把创建对象的任务交给容器, 程序中只需要依赖注⼊ (Dependency Injection,DI) 就可以了.

这个容器称为:IoC容器. Spring是⼀个IoC容器, 所以有时Spring 也称为Spring 容器

控制反转是⼀种思想, 在⽣活中也是处处体现.

⽐如⾃动驾驶, 传统驾驶⽅式, ⻋辆的横向和纵向驾驶 控制权由驾驶员来控制, 现在交给了驾驶⾃动化系统来控制, 这也是控制反转思想在⽣活中的实现.

⽐如招聘, 企业的员⼯招聘,⼊职, 解雇等控制权, 由⽼板转交给给HR(⼈⼒资源)来处理

IoC介绍

接下来我们通过案例来了解⼀下什么是IoC

需求: 造⼀辆⻋

传统程序开发

我们的实现思路是这样的:

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

在这里插入图片描述

最终程序的实现代码如下:

//Main.java
public class Main {
    public static void main(String[] args) {
        Car car=new Car();
        car.run();
    }
}
//Car.java
public class Car {
    private FrameWork frameWork;

    public Car() {
        frameWork=new FrameWork();
        System.out.println("car init...");
    }

    public void run(){
        System.out.println("car run...");
    }
}
//FrameWork.java
public class FrameWork {
    private  Bottom bottom;

    public FrameWork() {
        bottom=new Bottom();
        System.out.println("frameWork init...");
    }
}
//Bottom.java
public class Bottom {
    private Tire tire;

    public Bottom(){
        tire=new Tire();
        System.out.println("bottom init...");
    }
}
//Tire.java
public class Tire {
    private int size=17;

    public Tire(){
        System.out.println("tire init...");
    }
}
问题分析

这样的设计看起来没问题,但是可维护性却很低.

接下来需求有了变更: 随着对的⻋的需求量越来越⼤, 个性化需求也会越来越多,我们需要加⼯多种尺⼨的轮胎.

那这个时候就要对上⾯的程序进⾏修改了,修改后的代码如下所⽰:

在这里插入图片描述

修改之后, 其他调⽤程序也会报错, 我们需要继续修改

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

完整代码如下:

public class Main {
    public static void main(String[] args) {
        Car car=new Car(20);
        car.run();

        Car car2=new Car(21);
        car2.run();
    }
}

public class Car {
    private FrameWork frameWork;

    public Car(int size) {
        frameWork=new FrameWork(size);
        System.out.println("car init...");
    }

    public void run(){
        System.out.println("car run...");
    }
}

public class FrameWork {
    private  Bottom bottom;

    public FrameWork(int size) {
        bottom=new Bottom(size);
        System.out.println("frameWork init...");
    }
}

public class Bottom {
    private Tire tire;

    public Bottom(int size){
        tire=new Tire(size);
        System.out.println("bottom init...");
    }
}

public class Tire {
    private int size;

    public Tire(int size){
        this.size=size;
        System.out.println("tire init...size:"+size);
    }
}

从以上代码可以看出,以上程序的问题是:当最底层代码改动之后,整个调⽤链上的所有代码都需要修改.

程序的耦合度⾮常⾼(修改⼀处代码, 影响其他处的代码修改)

即一辆车需要知道车身是怎么样的,车身需要知道底盘是怎么样的,底盘需要知道轮子是怎么样的,耦合度就很高

解决方案

在上⾯的程序中, 我们是根据轮⼦的尺⼨设计的底盘,轮⼦的尺⼨⼀改,底盘的设计就得修改. 同样因为我们是根据底盘设计的⻋⾝,那么⻋⾝也得改,同理汽⻋设计也得改, 也就是整个设计⼏乎都得改

我们尝试换⼀种思路, 我们先设计汽⻋的⼤概样⼦,然后根据汽⻋的样⼦来设计⻋⾝,根据⻋⾝来设计底盘,最后根据底盘来设计轮⼦. 这时候,依赖关系就倒置过来了:轮⼦依赖底盘, 底盘依赖⻋⾝,⻋⾝依赖汽⻋

这就类似我们打造⼀辆完整的汽⻋, 如果所有的配件都是⾃⼰造,那么当客⼾需求发⽣改变的时候,⽐如轮胎的尺⼨不再是原来的尺⼨了,那我们要⾃⼰动⼿来改了,但如果我们是把轮胎外包出去,那么即使是轮胎的尺⼨发⽣改变了,我们只需要向代理⼯⼚下订单就⾏了,我们⾃⾝是不需要出⼒的.

在这里插入图片描述

如何来实现呢:

我们可以尝试不在每个类中⾃⼰创建下级类,如果⾃⼰创建下级类就会出现当下级类发⽣改变操作,⾃⼰也要跟着修改.

此时,我们只需要将原来由⾃⼰创建的下级类,改为传递的⽅式(也就是注⼊的⽅式),因为我们不需要在当前类中创建下级类了,所以下级类即使发⽣变化(创建或减少参数),当前类本⾝也⽆需修改任何代码,这样就完成了程序的解耦.

IoC程序开发

基于以上思路,我们把调⽤汽⻋的程序⽰例改造⼀下,把创建⼦类的⽅式,改为注⼊传递的⽅式.

具体实现代码如下:

public class Main {
    public static void main(String[] args) {
        Tire tire=new Tire(17,"red");
        Bottom bottom=new Bottom(tire);
        FrameWork frameWork=new FrameWork(bottom);
        Car car=new Car(frameWork);
        car.run();
    }
}

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 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 {
    private int size;
    private String color;

    public Tire(int size,String color) {
        this.size = size;
        this.color=color;
        System.out.println("tire init...size:"+size+",color:"+color);
    }
}

代码经过以上调整,⽆论底层类如何变化,整个调⽤链是不⽤做任何改变的,这样就完成了代码之间的解耦,从⽽实现了更加灵活、通⽤的程序设计了。

汽车只需要知道它需要一个车身,车身只需要知道它需要一个底盘,底盘只需要知道它需要轮子,不需要知道具体细节,就解耦合了

传统开发方法:自己做饭

想象一下,你每天晚上都要自己做饭吃。这个过程就类似于传统开发方法:

  1. 自行准备:你需要自己购买食材(类似于创建对象),准备调料,做每一道菜。
  2. 高耦合:每个步骤都依赖前一个步骤的完成,如果你忘了买某样食材,整个晚餐都可能无法完成。
  3. 灵活性差:如果突然有朋友来访,而你准备的食材和菜谱是固定的,很难快速适应增加的人数或特殊的饮食需求。
  4. 难以更换:一旦你决定做某个菜,就必须按照原计划进行,中途改变计划将会非常麻烦。

IoC(依赖注入)方法:外卖服务

现在,想象你改为使用一家提供全套餐服务的外卖(这就像是依赖注入):

  1. 服务提供:你只需要选择想吃什么,外卖服务提供完整的餐点,你不需要自己准备食材或调料。
  2. 解耦:你不依赖于具体的购物或烹饪过程,只需等待成品送达。
  3. 灵活性高:突然有更多人需要吃饭?只需增加订单数量或更改订单即可,无需自己重新准备。
  4. 易于更换:想改变菜单?只需取消当前订单,重新下一个新的订单即可。
IoC优势

在传统的代码中对象创建顺序是:Car -> Framework -> Bottom -> Tire

改进之后解耦的代码的对象创建顺序是:Tire -> Bottom -> Framework -> Car

在这里插入图片描述

我们发现了⼀个规律,通⽤程序的实现代码,类的创建顺序是反的,传统代码是 Car 控制并创建了Framework,Framework 创建并创建了 Bottom,依次往下,⽽改进之后的控制权发⽣的反转,不再是使⽤⽅对象创建并控制依赖对象了,⽽是把依赖对象注⼊将当前对象中,依赖对象的控制权不再由当前类控制了.

这样的话, 即使依赖类发⽣任何改变,当前类都是不受影响的,这就是典型的控制反转,也就是 IoC 的实现思想

到这⾥, 我们⼤概就知道了什么是控制反转了, 那什么是控制反转容器呢?也就是IoC容器

这部分代码, 就是IoC容器做的⼯作.

从上⾯也可以看出来, IoC容器具备以下优点:

资源不由使⽤资源的双⽅管理,⽽由不使⽤资源的第三⽅管理,这可以带来很多好处。第⼀,资源集中管理,实现资源的可配置和易管理。第⼆,降低了使⽤资源双⽅的依赖程度,也就是我们说的耦合度。

  1. 资源集中管理: IoC容器会帮我们管理⼀些资源(对象等), 我们需要使⽤时, 只需要从IoC容器中去取就可以了

  2. 我们在创建实例的时候不需要了解其中的细节, 降低了使⽤资源双⽅的依赖程度, 也就是耦合度.

Spring 就是⼀种IoC容器, 帮助我们来做了这些资源管理.

Spring帮我们管理对象,我们要做的:

  1. 告诉Spring帮我们管理哪些对象(
  2. 知道如何取出这些对象(

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

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

相关文章

DNS相关内容

一、dns的两种解析方式 1. 正向解析 将域名解析为 ip 地址 2. 逆向解析 将 ip 地址解析为域名 设置解析方式,都是在 zone 文件中 named.conf 解决权限 named.rfc1912.zone 解决解析方式 3.DNS 方向解析 把 192.168.71.145 这个 ip 地址逆向解析为 www.yuany…

Android逆向题解攻防世界-easyjava-难度6

纯Java实现,不涉及so, flag加密之后与指定字符串 “wigwrkaugala"比较判断,循环一个个字符加的,那可以一个个字符对应还原。 加密算法就在a,b类里面,代码直接复制到idea ,枚举暴力破解。 每一位输入范围a-z , 找…

Lua脚本 快速掌握

1.Lua脚本概述 Lua是一种轻量级的编程语言,由巴西里约热内卢天主教大学开发。设计初衷是为了嵌入应用程序中,提供灵活的配置和脚本能力。Lua具有简洁的语法和强大的扩展性,使得它在多个领域得到了广泛应用。 Lua的特点包括动态类型、自动内…

The Sandbox 游戏制作教程第 4 章|使用装备制作游戏,触发独特互动

欢迎回到我们的系列,我们将记录 The Sandbox Game Maker 的 “On-Equip”(装备)功能的多种用途。 如果你刚加入 The Sandbox,On-Equip 功能是 “可收集组件”(Collectable Component)中的一个多功能工具&a…

C++ list【常用接口、模拟实现等】

1. list的介绍及使用 1.1 list的介绍 1.list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。 2.list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前…

MyBatisPlus 第二天

常用注解 1 TableName:数据库表名和实体类名不同时,会出现以下报错 在实体类上添加 TableName("t_user") 在开发的过程中,我们经常遇到以上的问题,即实体类所对应的表都有固定的前缀,例如t_或tbl_此时,可以使用MyBa…

el-tree自定义节点内容

<el-tree :data"data" :props"defaultProps" ref"treeRef" show-checkbox check-change"handleCheckChange"><!-- 自定义节点内容 --><template #default"{ node, data, store }"><span class"tr…

无人值守人工智能智慧系统数据分析:深度洞察与未来展望

无人值守人工智能智慧系统数据分析&#xff1a;深度洞察与未来展望 随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;技术已逐渐渗透到社会经济的各个领域&#xff0c;其中无人值守人工智能智慧系统作为AI技术应用的前沿阵地&#xff0c;正引领着一场深刻的…

【数量关系】毛娃儿笔记

一、导学 1、比例的常见作用 &#xff08;1&#xff09;通过份数求数量 甲&#xff1a;乙1:2 那么甲乙的人数总和一定是3的倍数 &#xff08;2&#xff09;得到倍数关系 不同的说法都可以转化为比例&#xff0c;比如甲是乙的两倍2:1、甲是乙的4/34:3、甲比乙多25%5:4 &am…

基于vue框架的4S店汽车维修保养管理系统28a7y(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;客户,技师,车辆信息,财务,客户维修,维修分配,维修订单,保养预约,保养分配,保养订单,维修费用,保养费用 开题报告内容 基于Vue框架的4S店汽车维修保养管理系统 开题报告 一、项目背景与意义 随着汽车产业的迅猛发展&#xff0c;4S店作…

【微前端中常见的问题及其解决办法】

随着前端技术的飞速发展&#xff0c;大型应用系统的复杂性和规模性日益增加&#xff0c;传统的单体前端架构逐渐暴露出维护成本高、升级困难、技术栈单一等问题。为了应对这些挑战&#xff0c;微前端&#xff08;Micro-Frontends&#xff09;作为一种新的架构模式应运而生。微前…

自研Vue3低代码海报制作平台第一步:基础拖拽组件开发

学习来源&#xff1a;稀土掘金 - 幽月之格大佬的技术专栏可拖拽、缩放、旋转组件 - 著作&#xff1a;可拖拽、缩放、旋转组件实现细节 非常感谢大佬&#xff01;受益匪浅&#xff01; 前面我们学习了很多vue3的知识&#xff0c;是时候把它们用起来做一个有意思的平台&#xf…

合合信息OCR支持30类国内常见票据一站式分类识别,支持医疗发票、数电票识别

合合信息TextIn平台明星产品——国内通用票据识别&#xff0c;重磅更新&#xff01; 产品支持票据类型扩展到23大类、30小类&#xff0c;覆盖场景更全面&#xff0c;同时升级优化了多款票据识别模型&#xff0c;平均识别率较前版本提升11.5%&#xff0c;整体识别速度提升21.9%…

关于k8s的Pod控制器

目录 1.Pod控制器及其作用 2.pod控制器类型 2.1 ReplicaSet: 2.2 Deployment 2.3 DaemonSet 2.4 StatefulSet 2.5 Job 2.6 Cronjob 3.Pod与控制器之间的关系 3.1 Deployment 3.2 SatefulSet 3.3 DaemonSet 3.4 job 3.5 cronjob 1.Pod控制器及其作用 Pod控制器&am…

北京某银行成功替换F5!更多实施细节曝光→

随着国家对金融行业技术创新的持续关注&#xff0c;金融行业的诸多用户正积极开展业务系统的数字化创新。 在这一领域&#xff0c;保障业务稳定性和连续性始终是最重要的议题。今天&#xff0c;为大家介绍的最佳实践来自北京某银行&#xff0c;他们通过积极探索和评估&#xf…

Python酷库之旅-第三方库Pandas(078)

目录 一、用法精讲 321、pandas.Series.str.len方法 321-1、语法 321-2、参数 321-3、功能 321-4、返回值 321-5、说明 321-6、用法 321-6-1、数据准备 321-6-2、代码示例 321-6-3、结果输出 322、pandas.Series.str.ljust方法 322-1、语法 322-2、参数 322-3、…

HMAC算法:构建安全认证的基石

在信息安全领域&#xff0c;数据完整性和认证是至关重要的。HMAC&#xff08;Hash-based Message Authentication Code&#xff09;算法作为一种基于哈希的消息认证码&#xff0c;广泛应用于数据传输过程中的安全认证。本文将带你了解HMAC算法的原理、特点及其应用场景。 HMAC算…

全方位解析RAG技术:从概念理论到代码实操,一文助你掌握检索增强生成的精髓!

一、LLMs 已经具备了较强能力了&#xff0c;为什么还需要 RAG(检索增强生成)? 尽管 LLM 已展现出显著的能力&#xff0c;但以下几个挑战依然值得关注&#xff1a; 幻觉问题&#xff1a;LLM 采用基于统计的概率方法逐词生成文本&#xff0c;这一机制内在地导致其可能出现看似…

Git基础使用教程

版本控制手册 本文中出现的 [ ] 为根据需求自行修改的变量。 基本命令 git init&#xff1a;将当前目录配置成git仓库&#xff0c;信息记录在隐藏的.git文件夹中。 git config --global user.name [xxx]&#xff1a;设置全局用户名&#xff0c;信息记录在~/.gitconfig文件中。…

厦门商家微信小程序、抖音、支付宝小程序同步上线

想要迅速在厦门开设微信小程序店铺&#xff1f;乔拓云网站提供了简便快捷的解决方案。只需四步&#xff0c;轻松复制模板&#xff0c;定制内容&#xff0c;即可上线专属小程序。 首先&#xff0c;访问乔拓云官网&#xff0c;完成免费注册&#xff0c;轻松获得您的专属账号。不论…