认识Spring

news2025/7/8 11:18:23

1.1 Spring的历程

早期的 Java EE 使用 EJB 为核心的开发方式,但是这种开发方式在实际开发环境中存在诸多问题: 使用复杂, 代码臃肿, 移植性差等.
于是"Spring 之父" Rod Johnson 在其畅销书《Expert One-on-One J2EE Design and Development》中使用一个3万行代码的附件,展示在不使用EJB的情况下创建一个拓展性强, 高质量的 Java 应用程序, 随着这本著作的流行, Rod Johnson 把这份源码开源, 并把这个新框架命名为: “Spring”, 含义为: Spring 像一缕春风一样,扫平传统 J2EE 的寒冬.于是在2004年3月24日发布了 1.0 正式版本.

1.2 Spring的含义

广义的 Spring

广义上的Spring指的是以Spring Framework 为核心的 Spring 技术栈.
衍生的相关技术有: Spring Framework、Spring MVC、SpringBoot、Spring Cloud、Spring Data、Spring Security 等

狭义的 Spring

狭义的Spring: Spring Framework , 通常被称为Spring 框架
Spring 有两个核心部分: AOP 和 Ioc
AOP (Aspect Oriented Programming) 译为"面向切面编程" , 利用AOP 把为业务服务的但是不属于业务部分的逻辑封装,增加代码的复用性, 降低模块之间的耦合度,除此之外, AOP 还可以解决日志, 事物, 权限等系统层面的问题.
IOC (Inverse of Control ) 译为"控制反转", 指把创建对象过程交给 Spring 进行管理
用一句话概括Spring: Spring是包含众多工具方法的IoC容器.

什么是容器?

我们回忆之前学习的知识, 在Java中的List/Map是数据存储容器, 在Java Web中 的Tomcat 是 Web容器. 那么对应的Spring 就是 存储 IoC的容器.

什么是Ioc?

下面利用两种不同的方式构建Car对象来认识其区别.

假如你现在收到一个项目: 客户需要定制化的选择的新车的组件及其配件. 那么对于一个Car对象是由许多组件构成, 这些组件又由更多小组件组成,所以下面的就简化的提供一个依赖关系.

传统的程序开发:
传统开发采当需要下层对象时在当前类中 引入该对象 即可, 这样就会衍生出许多问题,先上代码

package Old;

public class CarExample {

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

    /**
     * 汽⻋对象
     */
    static class Car {
        private Framework framework;

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

        public void init() {
            // 依赖⻋身
            framework.init();
        }
    }

    /**
     * ⻋身类
     */
    static class Framework {
        private Bottom bottom;

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

        public void init() {
            // 依赖底盘
            bottom.init();
        }
    }

    /**
     * 底盘类
     */
    static class Bottom {
        private Tire tire;

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

        public void init() {
            // 依赖轮胎
            tire.init();
        }
    }

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

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

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

}

当前需求只是客制化轮胎尺寸,但是后期有了更多的需求,那么代码的改动就会很大,这就是代码的耦合度很高,那么如何降低耦合度呢? 那么就可以把控制权交给上级类,由上级类实现下级类的初始化.
控制反转式程序开发:
通过控制反转开发的手段,就可以实现模块之间的解耦,假如需求增加底盘的高度,车身的颜色,车身的材质,实现代码如下:

package New;


class CarExample {
    public static void main(String[] args) {
        // 自定义轮胎尺寸
        Tire tire = new Tire();
        tire.setSize(32);

        // 自定义底盘高度
        Bottom bottom = new Bottom(tire);
        bottom.setHeight(20);

        // 自定义车身的颜色和材质
        Framework framework = new Framework(bottom);
        framework.setColor("Green");
        framework.setMaterial("钛合金");

        // 最后将这些组件组装好
        Car car = new Car(framework);
    }

    /**
     * 汽⻋对象
     */
    static class Car {
        private Framework framework;

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

        public void init() {
            // 依赖⻋身
            framework.init();
        }
    }

    /**
     * ⻋身类
     */
    static class Framework {
        private Bottom bottom;
        private String color = "Red";
        private String material = "镀锌薄钢板";

        public void setColor(String color) {
            this.color = color;
        }

        public void setMaterial(String material) {
            this.material = material;
        }

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

        public void init() {
            // 依赖底盘
            bottom.init();
        }
    }

    /**
     * 底盘类
     */
    static class Bottom {
        private Tire tire;
        private int height = 10;

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

        public void setHeight(int height) {
            this.height = height;
        }

        public void init() {
            // 依赖轮胎
            tire.init();
            System.out.println("底盘高度: " + height);
        }
    }

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

        public Tire() {

        }

        public void setSize(int size) {
            this.size = size;
        }

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

因为通过传递的方式(也就是注入的方式), 我们不需要在当前类中创建下级类,即使下级类改变或者增加属性都不会影响当前类,当前类需要什么就通过set()方法设置好然后交付给上级类,从而降低类之间的耦合度.

对比总结:
在传统开发中采用的,Car对象控制并创建了Framework, Framework对象控制并创建了Bottom,依次向下,而修改后的代码的控制权发生了反转, 不再由是上级对象创建和控制了,而是把下级对象注入到当前对象中,于是下级对象内部改变不会影响到当前类,这就是典型的控制反转,也就是Ioc的实现思想.

再次理解Ioc

通过上述开发方式的转化,实现控制权的翻转,这是Ioc的一个特点,那么如何理解"Spring 是一个Ioc容器",那么对于容器所具备的特性;

  • 把物品存储到容器中
  • 把物品从容器从取出来

那么对应到Ioc容器中就是关于对象的存取操作: 把对象存储到Spring中,把对象从Spring中取出.

Spring是包含众多工具方法的容器,那么把对象存储到Ioc容器中就可以对容器中的工具"随用随取, 用完放回".不必在需要某个工具(对象)时才去创建, 和传统开发需要时创建有着很大区别.

对于传统开发中需要某个对象时就使用 new 去创建(二者之间的关系称为依赖, 比如底盘依赖于轮胎),不妨称 new 对象的类为"调用者", 被 new 的对象称为"被调用者" ,那么调用者掌握着被调用者的控制器,而在Spring中,由于把对象都’存储’到IoC容器中,调用方变成被动的去请求IoC容器创建对象,此时就发生明显的控制反转.

DI概述

DI (Dependency Injection 依赖注入),依赖注入不是一个设计思想,而是一个具体的实现技术,指的是在IoC容器运行期间动态的把依赖对象注入到当前对象中的技术就是DI.
例如 上面的Bottom(底盘类) 依赖 Tire(轮胎类) , 把Tire对象注入到Botom对象的操作就是DI(依赖注入)

    /**
     * 底盘类
     */
    static class Bottom {
        private Tire tire;
        private int height = 10;

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

        public void setHeight(int height) {
            this.height = height;
        }

        public void init() {
            // 依赖轮胎
            tire.init();
            System.out.println("底盘高度: " + height);
        }
    }

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

        public Tire() {

        }

        public void setSize(int size) {
            this.size = size;
        }

        public void init() {
            System.out.println("轮胎尺⼨:" + size);
        }
    }
    public static void main(String[] args) {

        Tire tire = new Tire();
        tire.setSize(32);

        // 把构造好的tire对象注入bottom对象的技术就是依赖注入.
        Bottom bottom = new Bottom(tire);
        bottom.setHeight(20);

    }

IoC 和 DI 的区别

共同点: 二者都是从不同的维度, 描述同一件事(如何实现程序的解耦, 达到控制权的反转)
不同点: IoC是实现的思想, DI是实现IoC思想的一个具体手段

比如今天的完满的完成了今天的任务,我决定要"奖励自己", 那么奖励自己是一个思想并没有具体的实现; 对应的DI就是如何具体的实现,如奖励自己玩游戏,吃KFC等.

1.3 Spring的特点

  1. 方便解耦, 简化开发

Spring是一个大容器,可以把对象的创建,依赖关系的维护等交付给Spring管理

  1. 更加简易的集成各种优秀框架

Spring可以支持对各种框架(Hibernate,MyBaits等)的直接支持.

  1. 降低 Java EE API 的使用难度

Spring对Java EE 中一些难用的API(JDBC,远程调用等)都提供了封装,上手难度大大降低

  1. 方便程序的调试

Spring 支持 JUnit4, 可以通过注解方便地测试 Spring 程序

  1. AOP 编程的支持

Spring 提供面向切面编程, 可以方便地实现对程序进行权限拦截和运行监控等功能

  1. 声明式事务的支持

只需要通过配置就可以完成对事务的管理,而无须手动编程

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

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

相关文章

MySQL8.0优化 - 锁 - 按加锁的方式划分:显示锁、隐式锁

文章目录学习资料锁的不同角度分类锁的分类图如下按加锁的方式划分:显示锁、隐式锁隐式锁显式锁学习资料 【MySQL数据库教程天花板,mysql安装到mysql高级,强!硬!-哔哩哔哩】 【阿里巴巴Java开发手册】https://www.w3…

[附源码]计算机毕业设计JAVA基于Java的快递驿站管理系统

[附源码]计算机毕业设计JAVA基于Java的快递驿站管理系统 项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: S…

车联网解决方案-最新全套文件

车联网解决方案-最新全套文件一、建设背景面临的挑战1、平台难以支撑高并发接入2、海量数据难以挖掘价值3、缺乏使能套件,开发效率低4、车联网的安全难以保证二、建设架构三、建设方案四、获取 - 车联网全套最新解决方案合集一、建设背景 面临的挑战 1、平台难以支…

Teams Tab App 代码深入浅出 - 配置页面

上一篇文章我们使用Teams Toolkit 来创建、运行 tab app。这篇文章我们深入来分析看一下tab app 的代码。 先打开代码目录,可以看到在 src 目录下有入口文件 index.tsx,然后在 components 目录下有更多的一些 tsx 文件,tsx 是 typescript的一…

实战十二:基于FM算法针对用户商品购买和浏览记录预测用户的行为 代码+数据

1.案例知识点 推荐系统任务描述:通过用户的历史行为(比如浏览记录、购买记录等等)准确的预测出用户未来的行为;好的推荐系统不仅如此,而且能够拓展用户的视野,帮助他们发现可能感兴趣的却不容易发现的item;同时将埋没在长尾中的好商品推荐给可能感兴趣的用户。FM推荐方法…

Qt5开发从入门到精通——第十一篇二节(Qt5 事件处理及实例——键盘事件及实例)

提示:欢迎小伙伴的点评✨✨,相互学习c/c应用开发。🍳🍳🍳 博主🧑🧑 本着开源的精神交流Qt开发的经验、将持续更新续章,为社区贡献博主自身的开源精神👩‍🚀 文…

基于DJYOS的UART驱动编写指导手册

1.概述 DJYOS设计通用的串口驱动模型,在此模型的基础上,移植到不同硬件平台时,只需提供若干硬件操作函数,即可完成串口驱动开发,使开发工作变得简单而快速执行效率高。 DJYOS源代码都有特定的存放位置, 建…

记录为小电机安装一个5012编码器(多摩川协议)的过程

目录 1. 编码器接口板介绍 2. 编码器接口板安装 3. 角度读取软件实现 4.总结 为了能得到更精确的角度,于是想要通过在测试电机上安装一个编码器来获取更精确的角度,方便日后调试或者校验使用,这里记录下操作的步骤。 1. 编码器接口板介绍…

Github Actions 自动同步到 Gitee

目录引言具体方案引言 平时开源代码一般已Github为主,但是会遇到网不好的情况,于是考虑将Github仓库自动同步到Gitee上,作为备份。考虑不能手动做这个事情,于是想到了Github Actions 自动化同步到Gitee中 具体方案 假设Github已…

Mybatis Plus一对多联表查询及分页解决方案

文章目录需求需求分析分页问题说明分页问题原因一对多场景一一对多场景二性能优化优化解决方案需求 查询用户信息列表,其中包含用户对应角色信息,页面检索条件有根据角色名称查询用户列表; 需求分析 一个用户对应多个角色,用户…

java计算机毕业设计ssm党支部在线学习

项目介绍 本党支部在线学习是针对目前学习的实际需求,从实际工作出发,对过去的学习系统存在的问题进行分析,完善用户的使用体会。采用计算机系统来管理信息,取代人工管理模式,查询便利,信息准确率高,节省了开支,提高了工作的效率。 本系统结合计算机系统的结构、概念、模型、原…

【深度学习】torch.utils.data.DataLoader相关用法 | dataloader数据加载器 | pytorch

文章目录前言一、DataLoader介绍二、DataLoader的子方法(可调用方法)前言 dataloader数据加载器属于是深度学习里面非常基础的一个概念了,基本所有的图像项目都会用上,这篇博客就把它的相关用法总结一下。 之所以要写这篇&#x…

1-1 开源许可证GPL, BSD, MIT, Mozilla, Apache, LGPL的介绍

文章目录前言开源许可证由来开源许可证类型开源许可证介绍GPL协议BSD协议MIT协议Mozilla许可Apache协议LGPL开源协议前言 开源许可证(Open source licenses),广义来讲是指一种被用于计算机软件或其他产品的,允许在指定的条款内使…

zMemif: go语言高性能网络库

简介 开发zMemif的主要动机是go有很高的处理能力,但是内置的udp库的确有些寒酸, 纯c开发效率又有些低,虽然可以用nff-go来实现go和dpdk的融合,但是cgo编译的确有点烦人,而且这个项目似乎也死了。然后考虑到容器的场景…

单点登录以及实现(前后端分离和前后端不分离方式)

本文主要使用springSecurity来实现,其他实现请参照其原理自行研究。 一,单系统登录机制 1、http无状态协议 web应用采用browser/server架构,http作为通信协议。http是无状态协议,浏览器的每一次请求,服务器会独立处…

谷粒学院(三) 项目前端知识

一、VS Code 1、插件安装 为方便后续开发,建议安装如下插件(红色矩形框标记的插件)2、创建项目 vscode本身没有新建项目的选项,所以要先创建一个空的文件夹,如project_xxxx。 然后打开vscode,再在vscode里面…

二维随机向量的数学期望E与协方差σ

目录 1. 二维随机向量(X,Y)的数学期望EX, EY 2. 二维随机向量函数zg(X,Y)的数学期望EZ 3. 二维随机向量(X,Y)的方差DX, DY 4. 二维随机向量的性质(和、积的数学期望E与方差D) 5. 二维随机向量的协方差COV和相关系数ρ 5.1 协方差COV定义 5.2 协方…

私有数据传参

在串口工具进行输入: echo 1 > /dev/myled0 ---->led1灯点亮 echo 0 > /dev/myled0 ---->led1灯熄灭 echo 1 > /dev/myled1 ---->led1灯点亮 echo 0 > /dev/myled1 ---->led1灯熄灭 echo 1 > /dev/myled2 ---->led1灯点亮 echo 0 >…

java计算机毕业设计springboot+vue员工管理系统

项目介绍 本员工管理系统是针对目前村委会管理的实际需求,从实际工作出发,对过去的员工管理系统存在的问题进行分析,完善用户的使用体会。采用计算机系统来管理信息,取代人工管理模式,查询便利,信息准确率高,节省了开支,提高了工作的效率。 本系统结合计算机系统的结构、概念、…

无线蓝牙耳机什么牌子好一点?2022年蓝牙耳机推荐

喜欢听音乐,自然离不开耳机的支持,一款优质且时尚的耳机,能够带来极致的音效,可是该如何选择合适的耳机,成为了摆在眼前一个很重要问题如果这个问题一直萦绕在你的脑海中,那么下面的选择相信定不会错。 TO…