【Spring】(一)Spring设计核心思想

news2024/11/16 17:46:39

文章目录

  • 一、初识 Spring
    • 1.1 什么是 Spring
    • 1.2 什么是 容器
    • 1.3 什么是 IoC
  • 二、对 IoC 的深入理解
    • 2.1 传统程序开发方式存在的问题
    • 2.2 控制反转式程序的开发
    • 2.3 对比总结
  • 三、对 Spring IoC 的理解
  • 四、DI 的概念
    • 4.1 什么是 DI
    • 4.2 DI 与 IoC的关系


一、初识 Spring

1.1 什么是 Spring

Spring 是一个开源的轻量级 Java 框架,旨在简化 Java 应用程序的开发。它提供了一个全面的编程和配置模型,用于构建各种类型的应用,包括企业级应用和独立的 Java 应用。Spring 的设计理念是基于依赖注入(Dependency Injection)和面向切面编程(Aspect-Oriented Programming),使得应用开发更加模块化、灵活和易于维护

用一句话概括 Spring 就是:Spring 是一个包含了众多工具的 IoC 容器

1.2 什么是 容器

所谓容器就是能够盛放东西的器皿,就好像水杯一样。而 Spring 就是一个容器,它的功能就是负责存储和管理应用中的各个组件(Bean),然后在使用的时候从 Spring 中取出需要的 Bean 对象。

1.3 什么是 IoC

IoC,即控制反转(Inversion of Control),是 Spring 框架的核心理念之一。它将应用程序的控制权从开发人员的手中反转,由 Spring 容器负责管理对象的生命周期以及依赖关系。在传统的程序设计中,开发人员需要负责手动创建和管理对象,但是在 IoC 容器中,开发人员只需要定义组件(Bean)的配置元数据,由容器负责实例化、装配和管理这些组件

二、对 IoC 的深入理解

如果初次理解 IoC,可能会觉得很困难,可以通过下面的例子帮助我们理解 IoC 的作用。

假如,现在需要使用程序来模拟一个简单制造汽车的过程,其实现思路如下:

  • 如果要造汽车Car,首先需要有车身Framework;
  • 如果需要造车身Framework,首先就需要有地盘Bottom;
  • 如果需要造地盘Bottom,首先就需要有轮子Tire。

上述过程,不难发现存在一个依赖链的关系,首先通过传统程序的开发方式,来感受一下其存在的问题。

2.1 传统程序开发方式存在的问题

下面是用传统方式编写的代码:

class Tire {
    private Integer size = 17;

    public void init(){
        System.out.println("do tire: size = " + size);
    }
}

class Bottom {
    private Tire tire;
    public Bottom(){
        this.tire = new Tire();
    }

    public void init(){
        tire.init();
        System.out.println("do bottom");
    }
}

class Framework {
    private Bottom bottom;
    public Framework(){
        bottom = new Bottom();
    }

    public void init(){
        bottom.init();
        System.out.println("do framework");
    }
}

 class Car {
    private Framework framework;
    public Car(){
        framework = new Framework();
    }

    public void init(){
        framework.init();
        System.out.println("do car");
    }
}


public class Tradition {
    public static void main(String[] args) {
        Car car = new Car();
        car.init();
    }
}

在上面的传统写法中,可以发现每个类之间的耦合度非常高,并且每个类都需要管理它所依赖的对象,即掌握着其依赖对象的控制权。此时如果用户的需求改变了,使用的轮子Tire不再是固定的尺寸,而是需要由用户自己输入尺寸的大小,此时Tire类的代码需要更改为:

class Tire {
    private Integer size = 17;

    public Tire(int size){
        this.size = size;
    }

    public void init(){
        System.out.println("do tire: size = " + size);
    }
}

此时发现,不改不要紧,但是一改问题就来了,由于各个类之间的高耦合性,使得后续所依赖前者的代码都需要进行修改。


class Bottom {
    private Tire tire;
    public Bottom(int size){
        this.tire = new Tire(size);
    }

    public void init(){
        tire.init();
        System.out.println("do bottom");
    }
}

class Framework {
    private Bottom bottom;
    public Framework(int size){
        bottom = new Bottom(size);
    }

    public void init(){
        bottom.init();
        System.out.println("do framework");
    }
}

 class Car {
    private Framework framework;
    public Car(int size){
        framework = new Framework(size);
    }

    public void init(){
        framework.init();
        System.out.println("do car");
    }
}

如果要后续要继续增加 Tire 类的属性,例如color,此时就还要需要从头来进行修改。那么如何解决这个缺陷呢?

上次代码出现这个缺陷的根本原因就在于:当前类将自己所依赖的类的控制权掌握在了自己的手中,即在自己类的内部调用的所依赖类的构造方法。因此解决这个问题的方法也非常简单,那就是不在自己的内部代码中创建所依赖的对象,而是通过参数传递的方式获取这个依赖对象,这就是控制权转移的思想,即 IoC。

2.2 控制反转式程序的开发

下面是转移控制权的代码写法,即将当前类所依赖的对象通过参数的方式进行传入:

class Tire {
    private Integer size = 17;

    public Tire(int size) {
        this.size = size;
    }

    public void init() {
        System.out.println("do tire: size = " + size);
    }
}


class Bottom {
    private Tire tire;

    public Bottom(Tire tire) {
        this.tire = tire;
    }

    public void init() {
        tire.init();
        System.out.println("do bottom");
    }
}

class Framework {
    private Bottom bottom;

    public Framework(Bottom bottom) {
        this.bottom = bottom;
    }

    public void init() {
        bottom.init();
        System.out.println("do framework");
    }
}

class Car {
    private Framework framework;

    public Car(Framework framework) {
        this.framework = framework;
    }

    public void init() {
        framework.init();
        System.out.println("do car");
    }
}

public class IoC {
    public static void main(String[] args) {
        Tire tire = new Tire(18, "red");
        Bottom bottom = new Bottom(tire);
        Framework framework = new Framework(bottom);
        Car car = new Car(framework);
        car.init();
    }
}

此时,如果用户需求又发生了改变,要求轮子 Tire 的颜色也要自己来挑选,此时更改的代码如下:

class Tire {
    private Integer size = 17;
    private String color;

    public Tire(int size, String color) {
        this.size = size;
        this.color = color;
    }

    public void init() {
        System.out.println("do tire: size = " + size + ", color = " + color);
    }
}

此时,只需要修改 Tire 类和创建 Tire 对象的代码,而不需要对其他代码进行修改。可以发现,即使底层类的改变也不会影响到整个调用链的改变,这样就实现了代码的解耦,从而实现了更加灵活、通用的程序设计方式。

2.3 对比总结

以下是传统代码和 IoC 形式代码的调用过程:

通过对比两种代码的实现方式不难发现:

  1. 两种代码中类的创建顺序是相反的:
    • 传统代码的创建顺序是由顶层 Car 类创建到底层 Tire 类,即:Car -> Framework -> Bottom -> Tire
    • 而 IoC 形式代码的创建顺序则是由底层 Tire 类创建到顶层 Car 类,即:Tire -> Bottom -> Frame -> Car
  2. 传统代码中,当前类掌握着自己所依赖对象的控制权,耦合度非常高,一旦底层代码修改了,整个调用链的代码都会修改
  3. IoC 形式的代码中,当前类通过参数传递的方式,将对所依赖对象的控制权进行反转,即不再有自己掌控,此时无论底层代码如何修改,也不会对整个调用链上的代码造成影响

三、对 Spring IoC 的理解

“Spring 是一个 包含众多工具的 IoC 容器” 这句话的理解非常重要,因为它揭示了 Spring 框架最核心的功能和优势。在这里,我们可以把 Spring IoC 容器比喻成一个大大的容器,用来存放应用程序中的各种对象(Bean)。这个容器不仅负责对象生命周期的管理,还实现了对象之间的依赖注入(DI),从而实现了控制反转。

既然 Spring 是容器,那么它的核心功能就可以分为两个:

1. 将对象存入容器

  • 程序员首先需要创建应用程序中的各种对象(Bean),这些对象代表应用程序中的不同组件和功能模块。
  • 然后通过配置文件(如XML、注解或者 Java 配置类)告诉 Spring IoC 容器如何创建这些对象,以及它们之间的依赖关系。
  • Spring IoC 容器会根据配置信息,在应用程序启动的时候负责实例化这些对象并存放到容器中,从而完成对象的创建和组装过程。

2. 从容器中取出对象

  • 一旦对象被存入了 Spring IoC 容器中,它们就可以在应用程序的其他部分被获取和使用。程序员不需要显示地创建对象,而是从 Spring 容器中直接获取已经创建好的对象来使用。
  • 通过依赖注入的方式,Spring IoC 容器会在合适的时候将依赖的对象自动注入到需要它们的地方。

总的来说,Spring IoC 容器负责管理对象的创建、组装和依赖关系,开发人员只需关注对象的定义和配置通过将对象存入容器并从容器中获取对象,Spring 实现了对象的控制反转,使得应用程序的开发更加简洁、灵活和易于维护。这也是 Spring 框架的核心之一,为开发者提供了一个强大且高度可定制的开发平台。

四、DI 的概念

4.1 什么是 DI

依赖注入(Dependency Injection,DI)是一种实现 IoC 的具体技术,它是 IoC 容器的一种表现形式。在 DI 中,对象之间的依赖关系不再有类自己创建和管理,而是有外部容器(如 Spring)来负责注入依赖的对象。简单来说,DI 就是将一个对象的依赖关系交给外部容器来处理,从而实现对象之间的解耦。

在 DI 中,通常由三种注入方式:

  1. 构造方法注入(Constructor Injection):通过构造函数接收依赖对象,这是最常见的注入方式。
  2. Setter 方法注入(Setter Injection):通过Setter方法设置依赖对象。
  3. 属性注入(Field Injection):通过属性的方式注入依赖对象。

DI 使得对象的依赖关系从代码中移出,变得可配置和灵活。通过使用DI,我们可以在应用程序的不同部分之间实现松耦合,提高代码的可测试性、可维护性和可扩展性。

4.2 DI 与 IoC的关系

DI(依赖注入)和 IoC(控制反转)是紧密相关的概念,通常同时被提及,它们之间的关系可以概括为:

  • IoC 是一种设计思想,它将应用程序的控制权从代码内部转移到外部容器。通过 IoC,对象的创建和依赖关系的管理被反转,交由容器来负责管理,而不是由代码显示的控制。
  • DI 是实现 IoC 的一种具体技术手段,它是 IoC 的一种表现形式。通过 DI,对象之间的依赖关系由外部容器来注入,而不是由对象自己来创建和管理依赖。

因此,DI 是 IoC 的一部分,它是实现 IoC 的重要手段。Spring 框架正是以 IoC 和 DI 为核心,提供了强大的 IoC 容器和依赖注入机制,从而实现了各种功能,如依赖管理、AOP、事务管理等。通过 IoC 和 DI,Spring 框架实现了松耦合、可配置和可扩展的应用程序开发。

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

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

相关文章

GoogLeNet卷积神经网络-笔记

GoogLeNet卷积神经网络-笔记 GoogLeNet是2014年ImageNet比赛的冠军, 它的主要特点是网络不仅有深度, 还在横向上具有“宽度”。 由于图像信息在空间尺寸上的巨大差异, 如何选择合适的卷积核来提取特征就显得比较困难了。 空间分布范围更广的…

性能测试jmeter连接数据库jdbc(sql server举例)

一、下载第三方工具包驱动数据库 1. 因为JMeter本身没有提供链接数据库的功能,所以我们需要借助第三方的工具包来实现。 (有这个jar包之后,jmeter可以发起jdbc请求,没有这个jar包,也有jdbc取样器,但不能发起…

Mysql面试突击班索引,事务与锁

Mysql面试突击班索引,事务与锁 1.为什么Mysql要使用B树做为索引而不用B树 B树能显著减少IO次数,提高效率B树的查询效率更加稳定,因为数据放在叶子节点B树能提高范围查询的效率,因为叶子节点指向下一个叶子节点B树采取顺序读 2.…

Mac直接使用Visio和MythType的解决办法

Mac使用 Visio 的三种解决办法及 Mac直接使用 MythType 的办法 今天终于在某种契机下解决了 Mac 下最大的不足,不能直接使用 Visio 和 MythType【2023年08月03日20:03:32】 摘要 众所周知在 mac 下无法直接使用 Visio 和 MythType,这导致我们&#xff0…

SSL 证书过期巡检脚本 (Python 版)

哈喽大家好,我是咸鱼 之前写了个 shell 版本的 SSL 证书过期巡检脚本 (文章:《SSL 证书过期巡检脚本》),后台反响还是很不错的 那么今天咸鱼给大家介绍一下 python 版本的 SSL 证书过期巡检脚本 (完整代码…

什么是跨链 DeFi?

跨链 DeFi 是指存在于多个不同区块链生态系统之间的金融应用程序生态系统,可以在彼此之间无缝交换数据和通证。 Web3 生态系统已经变得多链化,存在于数百个区块链、二层网络、应用链和其他环境的去中心化应用繁荣发展。虽然多样化的区块链生态系统的推出…

如何构建一套有效的培训系统

有效的培训系统对于组织的发展和员工的持续学习非常重要。一个好的培训系统可以提供全面的知识和技能,帮助员工不断成长和提升工作表现。 构建一个有效的培训系统需要确定培训目标。培训目标应该紧密与组织的战略目标相结合,明确员工需要掌握的技能和知…

SpringBoot 集成 Redis

本地Java连接Redis常见问题: bind配置请注释掉保护模式设置为noLinux系统的防火墙设置redis服务器的IP地址和密码是否正确忘记写访问redis的服务端口号和auth密码 集成Jedis jedis是什么 Jedis Client是Redis官网推荐的一个面向java客户端,库文件实现…

Centos7升级gcc、g++版本(转载)

Centos7默认的 gcc版本是 4.8.5 默认使用yum install gcc安装出来的gcc版本也是是4.8.5。 1.首先查看自己的 gcc 版本 gcc -v g -v如果出现:bash: g: 未找到命令... 则安装g:遇到暂停时,输入y继续安装 yum install gcc-c然后输入&#xf…

PGsql-安装

目录 方法一 方法二 方法一 安装:请点击进入,支持官网下载 免安装版,选择zip格式 选择对应的版本: 注意:如果要使用 Navicat 连接 PostgreSQL,建议选择低版本!! 高版本会出现的问…

元宇宙虚拟展厅的特点是什么呢?优势有哪些?

元宇宙是一个很广阔的虚拟世界,它可以创造出更为丰富、沉浸式的体验,这种全新的体验为展览和艺术领域带来了更多的可能性,元宇宙虚拟展厅以其多样化、互动性、沉浸式展示的特点,带领大家进入一个虚拟现实的全新世界。 元宇宙虚拟展…

如何下载Bootstrap?编译版与源码版有何区别?Bootstrap的编译版下载下来之后有哪些文件?

01-进入Bootstrap的官网 https://getbootstrap.com/ 02-右上角选择"All versions",或者直接通过URL进入版本选择界面: https://getbootstrap.com/docs/versions/ 03-在页面中根据自己的需要选择版本下载。 通常下载编译版(Compiled版)&#xff0c…

python 数据分析面试题:求分组排第n名的记录数据

近期面试遇到一个面试题,分享给大家。 文中会提供详细的解题思路以及问题延伸 一、面试题 面试题:输出各学科总分第一名的学员姓名、年龄、分数数据: class_a {name: [学员1, 学员2, 学员3, 学员4,学员5],age: [23, 24, 26, 27,25],course…

c高级:day2

1.思维导图 3.递归输出每个数 #include <myhead.h>void func(int num) {if (num/10 0){printf("%d\n", num);}else{func(num/10);printf("%d\n", num%10);} }int main(int argc, char *argv[]) {int num;printf("请输入一个数&#xff1a;&qu…

如何使用 ChatGPT 为 Midjourney 或 DALL-E 等 AI 图片生成提示词

人工智能为创意产业开辟了一个充满可能性的全新世界。人工智能最令人兴奋的应用之一是生成独特且原创的艺术品。Midjourney 和 DALL-E 是人工智能生成艺术的两个突出例子&#xff0c;吸引了艺术家和艺术爱好者的注意。在本文中&#xff0c;我们将探索如何使用 ChatGPT 生成 AI …

关于antDv table组件pagination分页器跳转页数置空(输入框)置空问题

需求开发需要实现antDv table组件pagination分页器跳转页数置空&#xff08;输入框&#xff09;置空 修改这红框内input的值 翻了组件文档发现没有这个组件配置&#xff0c;所以只能用原生操作dom更改值 this.$nextTick(() > {// 改变跳至 几页的值document.getElementsBy…

Web开发介绍以及Java sprint

这里写目录标题 Web开发开发模式 Java sprint引入方式基础语法基础语法输出语句 变量介绍具体演示 数据类型运算符和数据类型转换运算符数据类型转换 函数定义以及调用 js对象array对象&#xff0c;数组&#xff0c;类似于Java的array集合String对象 json对象js自定义对象json介…

微信小程序学习者必用笔记

1、全局配置 1.1 window节点常用配置 1.2 tabBar 注意&#xff1a;它是与 window 和 page 同级的 1.2.1 tabBar的6个组成部分 1.2.2 tabBar的结点配置项 1.2.3 每个tab项的配置选项 1.3 局部配置 2、新建小程序页面 3、常用组件标签 3.1 view&#xff1a;相当于…

sqlyog导出mysql数据字典

1.打开sqlyog执行sql获取字典数据 SELECTt.COLUMN_NAME AS 字段名,t.COLUMN_TYPE AS 数据类型,CASE IFNULL(t.COLUMN_DEFAULT,Null) WHEN THEN 空字符串 WHEN Null THEN NULL ELSE t.COLUMN_DEFAULT END AS 默认值,CASE t.IS_NULLABLE WHEN YES THEN 是 ELSE 否 END AS 是否…

HTML+CSS+JavaScript:全选与反选案例

一、需求 1、单击全选按钮&#xff0c;下面三个复选框自动选中&#xff0c;再次单击全选按钮&#xff0c;下面三个复选框自动取消选中 2、当下面三个复选框全都选中时&#xff0c;全选按钮自动选中&#xff0c;下面三个复选框至少有一个未选中&#xff0c;全选按钮自动取消选…