什么是Spring?什么是IOC?什么是DI?IOC和DI的关系? —— 零基础可无压力学习,带源码

news2024/11/27 0:25:17

🧸欢迎来到dream_ready的博客,📜相信您对这几篇博客也感兴趣o (ˉ▽ˉ;)

📜什么是SpringMVC?简单好理解!什么是应用分层?SpringMVC与应用分层的关系? 什么是三层架构?SpringMVC与三层架构的关系?

📜SpringIOC和DI的代码实现,Spring如何存取对象?@Controller、@Service、@Repository、@Component、@Configuration、@Bean DI详解

📜Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习-CSDN博客

🧸第二篇博客是该篇博客的下一篇哦,欢迎各位看官老爷阅读!


目录

1、什么是众多工具?

2、什么是容器?

3、什么是IOC?

4、IoC代码案例介绍

传统程序开发 —— 实现思路:

软件设计原则:高内聚低耦合

解决方案

IOC程序开发

IoC优势

DI讲解

什么是DI呢

IOC和DI的关系?


  • 本质上:Spring是一个包含众多工具的IOC容器
  • 应用上:它也是一个广泛使用的Java应用程序开发框架,用于构建企业级应用程序。

1、什么是众多工具?

工具"通常指的是Spring框架提供的各种辅助类、库、模块、和功能,这些帮助开发人员更轻松地构建、维护和扩展Java应用程序。这些工具是Spring框架的一部分,用于解决不同方面的开发任务和问题

比如Spring提供依赖注入、事务管理、数据访问工具等都属于工具的范畴

2、什么是容器?

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

Spring这个容器存取的是对象

生活中的水杯,垃圾桶,冰箱等等这些都是容器

包括在Spring前学习的List/Map是数据存储容器,Tomcat是Web容器

既然Spring是一个IOC(控制反转)容器,作为容器,那么它就具备两个最基本的功能:

Spring容器管理的主要是对象,这些对象,我们称之为“Bean”。我们把这些对象交由Spring管理,由Spring来负责对象的创建和销毁,我们程序只需要告诉Spring,哪些需要存,以及如何从Spring中取出对象

3、什么是IOC?

IoC是Spring的核心思想,也是常见的面试题,那什么是IoC呢?

IoC就是控制反转(Inversion of Control) ,也是就说Spring是一个“控制反转”的容器

咱代码中用到的 @Controller、@Service等注解就用了IOC,加上这些注解后,就会把这个对象交给Spring管理,Spring框架启动时就会加载该类

把对象交给Spring管理,这就是IoC思想

  • 什么是控制反转呢?  -  >  就是控制权反转
  • 什么的控制权发生了反转?  -  >  获得依赖对象的过程被反转了

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

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

控制反转是一种思想,在生活中也是处处体现

        比如自动驾驶,传统驾驶模式,车辆的横向和纵向驾驶控制权由驾驶员来控制,现在交给了驾驶自动化系统来控制,这也是控制反转思想在生活中的实现

        比如招聘,企业的员工招聘,入职,解雇等控制权,由老板转交给HR(人力资源)来处理

4、IoC代码案例介绍

接下来我们通过案例来了解一下什么是IOC

需求:造一辆车

传统程序开发 —— 实现思路:

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

代码如下:

友情提示:尽量自己复制代码线下试一下,此处为了方便讲解将其放到同一个文件下了,你写的时候可以改一下,每一个类单独放一个文件下,不过我的写法也没有错误

public class NewCarExample {
    public static void main(String[] args) {
        Car car = new Car();
        car.run();
    }
    /**
     * 汽⻋对象
     */
    static class Car {
        private Framework framework;

        public Car() {
            framework = new Framework();
            System.out.println("Car init....");
        }
        public void run(){
            System.out.println("Car run...");
        }
    }
    /**
     * ⻋⾝类
     */
    static class Framework {
        private Bottom bottom;
        public Framework() {
            bottom = new Bottom();
            System.out.println("Framework init...");
        }
    }
    /**
     * 底盘类
     */
    static class Bottom {
        private Tire tire;
        public Bottom() {
            this.tire = new Tire();
            System.out.println("Bottom init...");
        }
    }
    /**
     * 轮胎类
     */
    static class Tire {
        // 尺⼨
        private int size;
        public Tire(){
            this.size = 17;
            System.out.println("轮胎尺⼨:" + size);
        }
    }
}

问题分析:

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

如果接下来需求有了变更:随着对车的需求量越来越大,个性化需求也会越来越多,我们需要加工多种尺寸的轮胎

那这个时候就要对上面的程序进行修改了,修改后的代码如下:

我们的本意是想着只修改Tire这一个类的代码的,但是我们发现修改之后,其他调用程序也会报错,我们需要继续修改

完整代码如下:

public class NewCarExample {
    public static void main(String[] args) {
        Car car = new Car(20);
        car.run();
    }
    /**
     * 汽⻋对象
     */
    static 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...");
        }
    }
    /**
     * ⻋⾝类
     */
    static class Framework {
        private Bottom bottom;
        public Framework(int size) {
            bottom = new Bottom(size);
            System.out.println("Framework init...");
        }
    }
    /**
     * 底盘类
     */
    static class Bottom {
        private Tire tire;
        public Bottom(int size) {
            this.tire = new Tire(size);
            System.out.println("Bottom init...");
        }
    }
    /**
     * 轮胎类
     */
    static class Tire {
        // 尺⼨
        private int size;
        public Tire(int size){
            this.size = size;
            System.out.println("轮胎尺⼨:" + size);
        }
    }
}

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

修改一处代码,影响其他处的代码修改,就叫耦合

软件设计原则:高内聚低耦合

高内聚指的是:一个模块中各个元素之间的联系的紧密程度,如果各个元素(语句、程序段)之间的联系程度越高,则内聚性越高,即“高内聚”

低耦合指的是:软件中各个层、模块之间的依赖关联程序越低越好。修改一处代码,其他模块的代码改动越少越好

高内聚低耦合矛盾么?

不矛盾,高内聚指的是一个模块中各个元素之间联系的紧密程度,低耦合指的是各个模块之间的紧密程度

这就好比一个企业,包含很多部门,各个部门之间的关联关系要尽可能的小,一个部门发生问题,要尽可能降低对其他部门的影响,就是低耦合。但是部门内部员工关系要尽量紧密,遇到问题一起解决,克服,这就叫做高内聚

比如邻里邻居,楼上漏水,楼下遭殃,就是耦合。家庭一个成员生病,其他成员帮忙照顾,就叫内聚

一个家庭内部的关系越紧密越好,一个家庭尽可能少的影响另一个家庭,就是低耦合

解决方案

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

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

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

如何来实现呢:

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

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

IOC程序开发

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

public class IocCarExample {
    public static void main(String[] args) {
        Tire tire = new Tire(20);
        Bottom bottom = new Bottom(tire);
        Framework framework = new Framework(bottom);
        Car car = new Car(framework);
        car.run();
    }
    static 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...");
        }
    }
    static class Framework {
        private Bottom bottom;
        public Framework(Bottom bottom) {
            this.bottom = bottom;
            System.out.println("Framework init...");
        }
    }
    static class Bottom {
        private Tire tire;
        public Bottom(Tire tire) {
            this.tire = tire;
            System.out.println("Bottom init...");
        }
    }
    static class Tire {
        private int size;
        public Tire(int size) {
            this.size = size;
            System.out.println("轮胎尺⼨:" + size);
        }
    }
}

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

IoC优势

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

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

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

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

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

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

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

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

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

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

DI讲解

什么是DI呢

DI:依赖注入(Dependency Injection) 

容器在运行期间,动态的为应用程序提供运行时所依赖的资源,称之为依赖注入

程序运行时需要某个资源,此时容器就为其提供这个资源

从这点看,依赖注入(DI)和控制反转(IoC)是从不同的角度来描述同一件事情,就是指通过引入IOC容器,利用依赖关系注入的方式,实现对象之间的解耦

上述代码中,是通过构造函数的方式,把依赖对象注入到需要使用的对象中的

IOC和DI的关系?

        IOC是一种思想,也是“目标”,而思想只是一种指导原则,最终还是要有可行的落地方案,而DI就属于具体的实现。所以也可以说,DI是IOC的一种实现

        比如说我今天心情比较好,吃一顿好的犒劳犒劳自己,那么“吃一顿好的”是思想和目标(是IOC),但最后我是吃海底捞还是杨国福?这就是具体的实现,就是DI

该篇博客的下一篇博客,无缝衔接:

📜SpringIOC和DI的代码实现,Spring如何存取对象?@Controller、@Service、@Repository、@Component、@Configuration、@Bean DI详解

🧸欢迎您于百忙之中阅读这篇博客,📜希望这篇博客给您带来了一些帮助,祝您生活愉快!

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

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

相关文章

【Unity细节】为什么UI移动了锚点,中心点和位置,运行的时候还是不在设置的位置当中

👨‍💻个人主页:元宇宙-秩沅 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 本文由 秩沅 原创 😶‍🌫️收录于专栏:unity细节和bug 😶‍🌫️优质专栏 ⭐【…

从行车记录仪恢复已删除/丢失视频的方法

“我的车里有行车记录仪。几天前,当我下班回家时,一辆卡车不知从哪里冒出来撞向了我。我们的两辆车都损坏了,但幸运的是,没有人受伤。我曾与卡车司机就修理我的汽车进行过会面,但他说我有错。我需要查看我的行车记录仪…

微服务注册中心之安装+实例搭建zookeeper

1.下载安装包并上传到Linux服务器 Apache ZooKeeper 可以使用wget或者curl命令 wget http://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.7.1/apache-zookeeper-3.7.1-bin.tar.gz连接失败也可以本地下载之后上传到服务器 scp /本地/文件的/路径 用户名远程服务器IP或主…

(免费领源码)java#SSM#mysql基于响应式的网上书店系统27119-计算机毕业设计项目选题推荐

摘 要 随着信息技术在管理上越来越深入而广泛的应用,管理系统的实施在技术上已逐步成熟。管理系统是一个不断发展的新型学科,本文主要通过对响应式的网上书店系统的功能性需求分析,对系统的安全性和可扩展性进行了非功能性需求分析。在详细的…

【Proteus仿真】【Arduino单片机】OLED液晶显示

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真Arduino单片机控制器,使用IIC OLED液晶等。 主要功能: 系统运行后,OLED液晶显示各种图形、字符、图像。 二、软件设计 /* 作者:嗨小…

C++标准模板(STL)- 类型支持 (类型属性,is_bounded_array,is_unbounded_array)

类型特性 类型特性定义一个编译时基于模板的结构&#xff0c;以查询或修改类型的属性。 试图特化定义于 <type_traits> 头文件的模板导致未定义行为&#xff0c;除了 std::common_type 可依照其所描述特化。 定义于<type_traits>头文件的模板可以用不完整类型实例…

时间序列预测模型实战案例(八)(Informer)BestPaper论文模型Informer代码实战讲解

论文地址->Informer论文地址PDF点击即可阅读 代码地址-> 论文官方代码地址点击即可跳转下载GIthub链接 本文介绍 本篇博客带大家看的是Informer模型进行时间序列预测的实战案例&#xff0c;它是在2019年被提出并在ICLR 2020上被评为Best Paper&#xff0c;可以说Inform…

如何再kali中下载iwebsec靶场

这个靶场有三种搭建方法&#xff1a; 第一种是在线靶场&#xff1a;http://www.iwebsec.com:81/ 第二种是虚拟机版本的&#xff0c;直接下载到本地搭建 官网地址下载&#xff1a;http://www.iwebsec.com/ 而第三种就是利用docker搭建这个靶场&#xff0c;我这里是用kali进行…

【CIO人物展】厦门市妇幼保健院CIO李振叶:医院数字化转型是迈向智慧医院新时代的关键...

李振叶 本文由厦门市妇幼保健院CIO李振叶投递并参与《2023中国数智化转型升级优秀CIO》榜单/奖项评选。 大数据产业创新服务媒体 ——聚焦数据 改变商业 厦门市妇幼保健院&#xff08;厦门大学附属妇女儿童医院&#xff09;创建于1959年&#xff0c;是集保健、医疗、教学、科研…

代码随想录二刷Day 59

647. 回文子串 这个题的dp定义想不到&#xff0c;递推公式也想不到但是看题解都很容易理解&#xff0c;遍历顺序不太好理解。 class Solution { public:int countSubstrings(string s) {vector<vector<bool>> dp(s.size(), vector<bool>(s.size(), false)…

AI系统ChatGPT程序源码+AI绘画系统源码+支持GPT4.0+Midjourney绘画

一、AI创作系统 SparkAi创作系统是基于OpenAI很火的ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如…

2.JMeter压测接口

概述 今日目标&#xff1a; JMeter使用 配置线程组配置 HTTP 接口配置断言 配置响应断言配置断言响应时间 配置结果监听压测报告 接口准备聚合报告察看结果树其它 线程组配置详解 线程数Ramp-Up bug结束 JMeter使用 双击 ApacheJMeter.jar 启动&#xff0c;然后修改名称&a…

Linux笔记-对/dev/vda1和/dev/vda2的理解

首先是这张图&#xff1a; 对于&#xff1a; /dev/vda1和/dev/vda2 可以知道&#xff0c;这个机器是在虚拟机上的&#xff0c;从设备描述中可以看到&#xff0c;与IO有关。 问下ChatGPT 问&#xff1a;linux上 /dev/vda1 和 /dev/vda2是干嘛的 答&#xff1a; /dev/vda1和…

GPT技术的崛起:改变生活与挑战未来

GPT的广泛使用引发了许多关于其影响的讨论&#xff0c;包括可能对就业和互联网公司的存活造成挑战。在这篇博客中&#xff0c;我们将探讨这些问题&#xff0c;并分享我们自己在日常生活中如何使用GPT的经验。 1 GPT技术的广泛应用 GPT&#xff0c;或者通用预训练模型&#x…

软件开发项目文档系列之十一如何撰写系统部署方案

目录 1 引言1.1 编写目的1.2 定义1.3 预期读者1.4 参考资料 2 系统部署要求2.1 硬件要求2.2 软件要求 3 系统结构描述3.1 逻辑结构3.2 物理拓扑 4 系统部署方案4.1 服务器资源4.2 软件资源4.3 应用服务器部署4.3.1 部署描述4.3.2 系统软件4.3.3 系统软件配置 4.4 MYSQL数据库服…

Python 海龟绘图基础教学教案(一)

Python 海龟绘图——第 1 题 题目&#xff1a;绘制下面的图形 解析&#xff1a; 考察 turtle 基本命令&#xff0c;绘制直线&#xff0c;使用 forward&#xff0c;可缩写为 fd。 答案&#xff1a; import turtle as t t.fd(100) # 或者使用 t.forward(100) t.done() Python 海…

【linux进程控制(二)】进程等待--父进程是如何等待子进程死亡的?

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:Linux从入门到精通⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学更多操作系统知识   &#x1f51d;&#x1f51d; ) 这里写目录标题 1. 前言2. …

一 Java初探

初识Java Java是一门高级语言,如 Python、C、C++、Ruby 和 JavaScript一样。 那么要运行用高级语言编写的程序,必须将其转换为低级语言 (即“机器语言”)有两种将高级语言转换为低级语言的程序:解释器和编译器。解释器(interpreter): 读取并执行用高级语言编写的程序,如…

STM32存储左右互搏 SPI总线读写FLASH W25QXX

STM32存储左右互搏 SPI总线读写FLASH W25QXX FLASH是常用的一种非易失存储单元&#xff0c;W25QXX系列Flash有不同容量的型号&#xff0c;如W25Q64的容量为64Mbit&#xff0c;也就是8MByte。这里介绍STM32CUBEIDE开发平台HAL库操作W25Q各型号FLASH的例程。 W25QXX介绍 W25QX…

多层感知机什么是?有什么作用?解决什么问题?

什么是多层感知机&#xff1f; 多层感知机&#xff08;Multilayer Perceptron&#xff0c;简称 MLP&#xff09;是一种基本的人工神经网络模型&#xff0c;其结构由多个神经元组成的多层结构。它是一种前馈式神经网络&#xff0c;通常用于解决分类和回归问题。 MLP 的基本结构包…