【Spring】Spring 核心和设计思想

news2024/11/6 13:43:13

Spring 核心和设计思想

  • 1.什么是 Spring
    • 1.1 传统程序开发
    • 1.2 控制反转程序开发
  • 2.理解 Spring IoC

1.什么是 Spring

我们通常所说的 Spring 指的是 Spring Framework(Spring 框架),它是⼀个开源框架,有着活跃而庞大的社区,这就是它之所以能⻓久不衰的原因。Spring 支持广泛的应⽤场景,它可以让 Java 企业级的应⽤程序开发起来更简单。

⽤⼀句话概括 Spring:Spring 是包含了众多⼯具⽅法的 IoC 容器。

由此引发的问题是:什么是容器? 什么又是 IoC 容器呢?

  • 什么是容器?容纳某种物品的装置。比如数据结构中的 List / Map(容纳数据)等等,包括 Tomcat(Web 容器)。
  • 什么是 IoC 呢?IoC 实际上是 控制反转Inversion of Control)的意思。

如何理解控制反转?

1.1 传统程序开发

假设我们去构建一辆车,利用传统的程序思想进行开发。
在这里插入图片描述

构建⼀辆 Car Class),然⽽⻋需要依赖 ⻋身Framework Class),⽽⻋身需要依赖 底盘Bottom Class),⽽底盘需要依赖 轮胎Tire Class),最终程序的实现代码如下。

package com.pp.reflection;

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

    /**
     * 汽车对象
     */
    static class Car {
        public void init() {            
            // 依赖车身
            Framework framework = new Framework();
            framework.init();
        }
    }

    /**
     * 车身类
     */
    static class Framework {
        public void init() {            
            // 依赖底盘
            Bottom bottom = new Bottom();
            bottom.init();
        }
    }

    /**
     * 底盘类
     */
    static class Bottom {
        public void init() {            
            // 依赖轮胎
            Tire tire = new Tire();
            tire.init();
        }
    }

    /**
     * 轮胎类
     */
    static class Tire {        
        // 尺寸
        private int size = 30;

        public void init() {
            System.out.println("轮胎尺寸:" + size);
        }
    }
}

通过代码我们发现了一些规律,Car 类依赖于 Framework,也就是 new Car 的时候,Framework 也被创建了,并且调用 init 方法,接下来调用的 init 方法又自动去 new Bottom,因为通过这些类的含义知道,他们之间是相互依赖的,如果你想去建造一辆车,就需要去保证这种依赖关系。

但是这种设计思想也有缺陷,当你满足不同客户的需求的时候,轮胎的尺寸不同,你就要去修改参数,又或者你想加别的参数,可能解决方法是,在每个类中加上参数,通过参数传递就行了呀。实际上这种方式问题很大,因为这几个类的依赖性很强,我们不断的因为客户的需求而修改类的代码是很麻烦而且很容易出 Bug 的行为。

传统程序开发的缺陷:以上程序中,轮胎的尺⼨的固定的,然⽽随着对的⻋的需求量越来越⼤,个性化需求也会越来越多,这时候我们就需要加⼯多种尺⼨的轮胎,那这个时候就要对上⾯的程序进⾏修改了。

package com.pp.reflection;

public class NewCarExample2 {

    public static void main(String[] args) {
        Car car = new Car();
        car.init(50, "猛男粉");
    }

    /**
     * 汽车对象
     */
    static class Car {
        public void init(int size, String color) {
            // 依赖车身
            Framework framework = new Framework();
            framework.init(size, color);
        }
    }

    /**
     * 车身类
     */
    static class Framework {
        public void init(int size, String color) {
            // 依赖底盘
            Bottom bottom = new Bottom();
            bottom.init(size, color);
        }
    }

    /**
     * 底盘类
     */
    static class Bottom {

        public void init(int size, String color) {
            // 依赖轮胎
            Tire tire = new Tire();
            tire.init(size, color);
        }
    }

    /**
     * 轮胎类
     */
    static class Tire {
        // 尺寸
        // private int size = 30;

        public void init(int size, String color) {
            System.out.println("轮胎尺寸:" + size + " | 颜色:" + color);
        }
    }
}

这种就是不断的修改类中的代码,实际上并不能完全解决问题反而会出很大的问题。

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

我们可以尝试不在每个类中⾃⼰创建下级类,如果⾃⼰创建下级类就会出现当下级类发⽣改变操作,⾃⼰也要跟着修改。此时,我们只需要将原来由⾃⼰创建的下级类,改为传递的⽅式(也就是 注入 的⽅式),因为我们不需要在当前类中创建下级类了,所以下级类即使发⽣变化(创建或减少参数),当前类本身也⽆需修改任何代码,这样就完成了程序的解耦。解决传统开发中的缺陷。

🚀 解耦 指的是解决了代码的耦合性,耦合性也可以换⼀种叫法,叫程序相关性。好的程序代码的耦合性(代码之间的相关性)是很低的,也就是代码之间要实现解耦。

实际上 IoC 就是解耦操作。

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

1.2 控制反转程序开发

基于上述思路,之前我们是通过在构造方法中创建依赖类的方法。现在换一种思路就是改为 依赖注入 的方法。

package com.pp.reflection;

public class IocCarExample {
    public static void main(String[] args) {
        Tire tire = new Tire(50, "红色");
        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;
        }

        public void run() {
            framework.init();
        }
    }

    static class Framework {
        private Bottom bottom;

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

        public void init() {
            bottom.init();
        }
    }

    static class Bottom {
        private Tire tire;

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

        public void init() {
            tire.init();
        }
    }

    static class Tire {
        private int size;

        private String color;

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

        public void init() {
            System.out.println("轮胎:" + size + " | 颜色:" + color);
        }
    }
}

仔细观察这种代码跟上面的有什么区别?这是很重要的一点。

当我们 new Car 的时候,已经创建好了 framework,并将 framework 注入到 car 的构造方法中,并且 car.run 中去执行 frameworkinit 方法。每个类的 init 方法实际上都是去执行下一个类的 init 方法。

这种代码是很精妙的,解决了前面的问题。无论我们怎么去改或者加多少个参数,都是很简单的事情,只需要在 new Tire 那里和 Tire 类本身进行修改即可。这就是 IoC 思想。

接下里的两张图可以进行对比一下。
在这里插入图片描述
我们发现了⼀个规律:通⽤程序的实现代码,类的创建顺序是反的,传统代码是 Car 控制并创建了 Framework,Framework 创建并创建了 Bottom,依次往下。⽽改进之后的控制权发⽣的反转,不再是上级对象创建并控制下级对象了,⽽是下级对象把注⼊将当前对象中,下级的控制权不再由上级类控制 了,这样即使下级类发⽣任何改变,当前类都是不受影响的,这就是典型的控制反转,也就是 IoC 的实现思想。

在传统设计里面,我们 new 的是 Car,但是改的是 Tire,由于改了 Tire 就要改 Bottom 等等。在 IoC 中,我们通过注入依赖的方式,改的还是 Tire,但是我们已经将 Tire 注入到 Bottom 中去了,所以 Bottom 也随之改变了,之后也是如此,所以他主要是对之前的控制顺序进行了反转,所以 IoC 叫做 控制反转

IoC 的设计思想说完了,那么如何去理解 Spring 是一个 IoC 容器呢?

2.理解 Spring IoC

既然 Spring 是⼀个 IoC 容器,重点还在 容器 ⼆字上,那么它就具备两个最基础的功能:

  • 1️⃣ 将对象存⼊到容器;
  • 2️⃣ 从容器中取出对象。

也就是说学 Spring 最核⼼的功能,就是 学如何将对象存⼊到 Spring 中,再从 Spring 中获取对象的过程

将对象存放到容器中的好处:将对象存储在 IoC 容器相当于将以后可能⽤的所有⼯具制作好都放到仓库中,需要的时候直接取就⾏了,⽤完再把它放回到仓库。⽽ new 对象的⽅式相当于,每次需要⼯具了,才现做,⽤完就扔掉了,也不会保存,下次再⽤的时候还得重新做。这就是 IoC 容器和普通程序开发的区别。

Spring 是⼀个 IoC 容器,说的是 对象的创建和销毁的权利都交给 Spring 来管理了,它本身⼜具备了存储对象和获取对象的能⼒

说到 IoC 不得不提的⼀个词就是 DIDependency Injection),即 依赖注⼊。所谓依赖注⼊,就是由 IoC 容器在运⾏期间,动态地将某种依赖关系注⼊到对象之中。所以,依赖注⼊(DI)和控制反转(IoC)是从不同的⻆度的描述的同⼀件事情,就是指通过引⼊ IoC 容器,利⽤依赖关系注⼊的⽅式,实现对象之间的解耦。IoC 是⽬标,也是⼀种思想,⽽⽬标和思想只是⼀种指导原则,最终还是要有可⾏的落地⽅案,⽽ DI 就属于具体的实现。DI 就是我们讲的依赖注入的实现,通过将下级类注入进去的具体实现。

所以建议大家多去看看这种通过注入方式来实现的代码,这对我们如何去设计代码是很重要的。

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

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

相关文章

白盒测试基本概念(学习笔记)

1.1白盒测试基本概念 测试工作中我们经常遇到的两种测试,就是白盒测试和黑盒测试。基本概念区分如下: 软件的白盒测试是对软件的过程性细节做细致的检查。这一方法是把测试对象看作一个打开的盒子,它允许测试人员利用程序内部的逻辑结构及有…

Mybatis使用和原理

Mybatis使用和原理 1、ORM架构2、Spring整合MyBatis使用2.1 添加maven依赖2.2 配置数据源2.3 创建实体类2.4 创建 MyBatis Mapper2.4.1 使用MyBatis注解2.4.2 使用XML方式 2.5 Service 层 3、Spring整合Hibernate使用3.1 添加maven依赖3.2 配置数据源3.3 创建实体类3.4 创建 Re…

C++核心编程和桌面应用开发 第十七天(set和multiset容器 pair map和multimap容器)

目录 1.set和multiset容器 1.1构造和赋值 1.2交换和大小 1.3插入和删除 1.4统计和查找 1.5pair对组 1.6set和multiset的区别 1.7指定内置数据类型排序规则 1.8指定自定义数据类型排序规则 2.map和multimap容器 2.1构造和赋值 2.2交换和大小 2.3插入和删除 2.4统计…

Android中常用adb命令

目录 1.adb连接安卓模拟器 2.adb列出所有已经连接的设备 3.adb显示设备的日志信息 4.adb 电脑文件推送到安卓模拟器中 5.adb 手机传送文件到电脑 6.adb获取安卓应用的包名和Activity名 附录 1--命令 1)adb devices 2)adb install 路径> 3)…

机器学习算法之回归算法

一、回归算法思维导图 二、算法概念、原理、应用场景和实例代码 1、线性回归 1.1、概念 ‌‌线性回归算法是一种统计分析方法,用于确定两种或两种以上变量之间的定量关系。‌ 线性回归算法通过建立线性方程来预测因变量(y)和一个或多个自变量…

SpringBoot项目如何设置定时任务总开关

目录 方法一:使用Spring Profiles 1.1 步骤1 1.2 步骤2 1.3 步骤3 1.4 步骤4 方法二:使用ConditionalOnProperty 2.1 步骤1 2.2 步骤2 2.3 步骤3 方法三: 主启动类禁用EnableScheduling 定时任务原理剖析(选看&#xf…

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-21

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-21 目录 文章目录 计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-21目录1. The Fair Language Model Paradox摘要研究背景问题与挑战如何解决创新点算法模型实验效果重要数据与结论推荐阅读指数&…

Python——实时域名通信状态监控

在互联网时代,网站和在线服务的可用性对于个人和企业都至关重要。域名的通信状态直接关系到服务的可达性,因此,实时监控域名的通信状态成为了一项基本需求。本文将详细介绍一个使用Python编写的简单域名通信状态监控工具,该工具能…

vue vxeui 上传组件 vxe-upload 全局配置上传方法,显示上传进度,最完美的配置方案

Vxe UI 上传组件 vxe-upload 全局配置上传方法,显示上传进度,最完美的配置方案 正常使用上传组件 vxe-upload,都是在用的时候传自定义上传方法,然后进行处理。几个页面是没什么问题,当系统页面非常多的时候&#xff0…

springboot 修复 Spring Framework 特定条件下目录遍历漏洞(CVE-2024-38819)

刚解决Spring Framework 特定条件下目录遍历漏洞(CVE-2024-38816)没几天,又来一个新的,真是哭笑不得啊。 springboot 修复 Spring Framework 特定条件下目录遍历漏洞(CVE-2024-38816)https://blog.csdn.ne…

SSH登录介绍

说明:一般登录服务器,我们可以用远程连接工具,如XShell、Windterm等,或者通过公司搭建的JumpServer(跳板机、堡垒机)来连接。前者是点对点登录,输入主机、端口,通过SSH协议登录&…

Unity计算二维向量夹角余弦值和正弦值的优化方法参考

如果不考虑优化问题,计算两个向量的余弦值或者正弦值可以直接使用类似的方法: [SerializeField] Vector2 v1, v2;void Start() {float valCos Mathf.Acos(Vector2.SignedAngle(v1, v2));float valSin Mathf.Asin(Vector2.SignedAngle(v1, v2)); } 但是…

理解 CSS 中的绝对定位与 Flex 布局混用

理解 CSS 中的绝对定位与 Flex 布局混用 在现代网页设计中,CSS 布局技术如 flex 和绝对定位被广泛使用。然而,这两者结合使用时,可能会导致一些意想不到的布局问题。本文将探讨如何正确使用绝对定位元素,避免它们受到 flex 布局的…

JAVA力扣每日一题:P3216. 交换后字典序最小的字符串

本题来自&#xff1a;力扣-每日一题 力扣 (LeetCode) 全球极客挚爱的技术成长平台https://leetcode.cn/ 题解&#xff1a; class Solution {public String getSmallestString(String s) {int len s.length();int[] arr new int[len];for (int i 0; i < len; i) {arr[i…

Vue3 学习笔记(十二)侦听器详解

在 Vue 3 中&#xff0c;侦听器是一种响应式特性&#xff0c;允许你观察和响应 Vue 实例上的数据变动。Vue 提供了 watch 和 watchEffect 两个函数来创建侦听器。 1、watch 侦听器 watch 是一个用于侦听特定数据源变化的函数。它允许你指定一个或多个数据源&#xff0c;并在这些…

#渗透测试#SRC漏洞挖掘# 信息收集-常见端口及谷歌语法

免责声明 本教程仅为合法的教学目的而准备&#xff0c;严禁用于任何形式的违法犯罪活动及其他商业行为&#xff0c;在使用本教程前&#xff0c;您应确保该行为符合当地的法律法规&#xff0c;继续阅读即表示您需自行承担所有操作的后果&#xff0c;如有异议&#xff0c;请立即停…

SAP ABAP开发学习——第一代增强(包含增强演示)

​​​​​​SAP ABAP开发学习——第二代增强&#xff08;包含增强演示&#xff09;-CSDN博客 SAP ABAP开发学习——第三代增强&#xff08;BADI)-CSDN博客 概念 第一代增强(增强嵌入标准程序中) 第一代出口-User exit 以SD用户出口为例 SD及MM较多的程序都是基于源码控制来…

安宝特分享 | AR技术引领:跨国工业远程协作创新模式

在当今高度互联的工业环境中&#xff0c;跨国合作与沟通变得日益重要。然而&#xff0c;语言障碍常常成为高效协作的绊脚石。安宝特AR眼镜凭借其强大的多语言自动翻译和播报功能&#xff0c;正在改变这一局面&#xff0c;让远程协作变得更加顺畅。 01 多语言翻译优势 安宝特A…

动态规划 01背包(算法)

现有四个物品&#xff0c;小偷的背包容量为8&#xff0c;怎么可以偷得价值较多的物品 如: 物品编号&#xff1a; 1 2 3 4 物品容量&#xff1a; 2 3 4 5 物品价值&#xff1a; 3 4 5 8 记f(k,w) ,当背包容量为w,可以偷k件物品…

AWD挨打记录

前言 昨天参加了星盟的AWD集训&#xff0c;本来寻思能猛猛乱杀&#xff0c;结果加固时间只有20分钟&#xff0c;WAF还没push上去就被三家上了不死马QAQ cms是站帮主&#xff0c;之前没打过&#xff0c;D盾啥也没扫出来&#xff0c;还寻思是个贼安全的系统&#xff0c;结果洞满…