JavaEE 突击 2 - Spring 核心与设计思想

Spring 核心与设计思想

  • 一 . Spring 是什么 ?
    • 1.1 容器
    • 1.2 IoC
      • 1.2.1 传统程序开发
      • 1.2.2 IoC 开发
      • 1.2.3 对比
    • 1.3 Spring 的 IoC
    • 1.4 DI

大家好 , 这个专栏给大家介绍一下 Java 家族的核心产品 - SSM 框架

Java 语言能走到现在 , 仍然屹立不衰的原因 , 有一部分就是因为 SSM 框架的存在

接下来 , 博主会带大家了解一下 Spring、Spring Boot、Spring MVC、MyBatis 相关知识点

并且带领大家进行环境的配置 , 让大家真正用好框架、学懂框架

在这里插入图片描述

一 . Spring 是什么 ?

我们通常所说的 Spring 指的是 Spring Framework (Spring 框架) , 它是⼀个开源框架 , 有着活跃而庞大的社区 , 这就是它之所以能长久不衰的原因 .
Spring 支持广泛的应用场景 , 他可以让 Java 企业级的应用程序开发起来更加容易 .
那么用一句话概括 Spring : Spring 是包含了众多工具方法的 IoC 容器 .
那么在这里面 , 出现了两个关键术语 : IoC 以及 容器 , 我们分别来看

1.1 容器

我们其实之前接触过这个概念 , 之前讲 Tomcat 的时候 , 提到了 Tomcat 其实就是一个 webapp 容器 , 因为我们可以把想要部署的项目拷贝到 Tomcat 里面的 webapps 目录下面 , 启动 Tomcat 之后就可以通过 127.0.0.1:8080 进行访问了 , 那么这里面 Tomcat 就起到了一个容器的作用 , 容纳了我们的 web 程序然后可以进行部署 .
所以 Tomcat 就是一个 Web 容器 .
那我们之前还学过数据结构 , 学习过顺序表/链表 , 也学习过 Map , 他们也都是用来存储数据的 , 那么它们也是一种容器 , 是用来存储数据的容器 .

1.2 IoC

很多人是不知道这个概念具体是怎么回事的 , 甚至可能都没听说过 .
那么我们先来看一下 , Ioc 的全称是 Inversion of Control , 意思就是 控制反转 .
那么我们之前说过的 Spring 就可以这样解释 : Spring 是一个包含了众多工具方法的 控制反转 的容器 ,
那翻译过来咱们也不是太懂啊 .
举个栗子 :
我们之前在 A 类里面想要使用 B 类该怎么办呢 ?
我们需要在 A 类 里面去 new B 类 , 那么这时候程序的控制权在 A 类手中 , A 类去决定 B 类是否创建 , 相当于 A 类控制着 B 类的生存权
那么控制反转就是 Spring 给我们提供了一种方式 , 我们要在 A 类里面使用 B , 但是我们不需要在 A 类里面去 new B 类了(就不需要 A 类控制 B 类的生存权了) , 我们把 B 类的生死决定权交给 Spring , Spring 是一个框架 , 是存在于程序之外的 , 我们的决定权就从 A 类 到 Spring 了 , 这就是控制反转
实际上 , 通过例子 , 我们可以得出 : 这个 控制反转 我们可以这样理解 , 叫做 控制(权)反转
那么我们再通过一个具体的代码例子给大家分析一下

1.2.1 传统程序开发

假如 , 我们现在构建⼀辆 “车” 的程序 , 我们的实现思路是这样的:
JavaEE 突击 2 - Spring 核心与设计思想_第1张图片

package car;

public class Tire {
    private int size = 17;//假如我们刚开始设计汽车 , 规定轮胎尺寸为 17

    // 接下来 , 我们开始组装轮胎
    public void init() {
        System.out.println("轮胎的尺寸:" + size);
    }
}

然后我们组装底盘

package car;

public class Bottom {
    private Tire tire;//告知一下我们需要轮胎

    //制造轮胎
    public Bottom() {
        tire = new Tire();
    }

    public void init() {
        System.out.println("底盘组装");
        // 但是底盘组装我们还需要先组装轮胎
        tire.init();
    }
}

接下来组装车身

package car;

public class FrameWork {
    private Bottom bottom;//组装车身需要底盘

    // 拿到底盘
    public FrameWork() {
        bottom = new Bottom();
    }

    public void init() {
        System.out.println("车身组装");
        // 组装车身需要先组装底盘
        bottom.init();
    }
}

最后组装我们的车

public class Car {
    private FrameWork frameWork;//组装车需要车身

    // 拿到车身
    public Car() {
        frameWork = new FrameWork();
    }

    public void init() {
        System.out.println("组装汽车");
        // 组装汽车需要先组装车身
        frameWork.init();
    }

    // 车组装之后 , 我们就可以开了
    public static void main(String[] args) {
        // 构建并运行车
        Car car = new Car();
        car.init();
    }
}

那么这个步骤可以视为最刚开始汽车的构建过程 , 那么有的人可能觉得这轮胎有点小 , 要跑越野的话不够用 , 那么就需要加大轮胎属性 , 那么所幸我们把这个尺寸交给用户 , 让他们提意见
注 : 下面的代码都存在语法错误 , 只是为了举例
轮胎 :

package car;

public class Tire {
    private int size = 17;//假如我们刚开始设计汽车,规定轮胎尺寸为 17

    // 让用户自己决定尺寸
    public Tire(int size) {
        this.size = size;
    }
    // 接下来,我们开始组装轮胎
    public void init() {
        System.out.println("轮胎的尺寸:" + size);
    }
}

底盘 :

package car;

public class Bottom {
    private Tire tire;//组装底盘需要轮胎

    //拿到轮胎
    //因为我们的轮胎需要传入属性,那么这个属性从哪里来,就得是作为参数传进来
    public Bottom(int size) {
        tire = new Tire(size);
    }

    public void init() {
        System.out.println("底盘组装");
        // 但是底盘组装我们还需要先组装轮胎
        tire.init();
    }
}

车身 :

package car;

public class FrameWork {
    private Bottom bottom;//组装车身需要底盘

    // 拿到底盘
    public FrameWork(int size) {
        bottom = new Bottom(size);
    }

    public void init() {
        System.out.println("车身组装");
        // 组装车身需要先组装底盘
        bottom.init();
    }
}

车 :

package car;

public class Car {
    private FrameWork frameWork;//组装车需要车身

    // 拿到车身
    public Car(int size) {
        frameWork = new FrameWork(size);
    }

    public void init() {
        System.out.println("组装汽车");
        // 组装汽车需要先组装车身
        frameWork.init();
    }

    // 车组装之后 , 我们就可以开了
    public static void main(String[] args) {
        int size = 15;//假设用户决定的尺寸
        // 构建并运行车
        Car car = new Car(size);
        car.init();
    }
}

JavaEE 突击 2 - Spring 核心与设计思想_第2张图片

这就产生了一个问题 : 当底层类发生改变的时候 , 整个调用链上的所有代码都要进行相应的修改
这样咱们的代码 耦合度 是非常高的

耦合度 : 又叫做 “相关性” , 当一个类发生改变 , 另一个类也要相应的做出改变 , 这个过程就叫做 “耦合”

那么假如我们增加了需求 , 要修改的地方会非常多 , 那么传统程序开发的思路就会十分复杂 , 这种情况下我们的 Ioc 思想会简化操作 , 减少耦合

1.2.2 IoC 开发

我们先把需要用到的所有类创建出来
然后再把每个类里面的 init 方法写出来
CarPlus :

package newcar;

public class CarPlus {
    //虽然使用 IoC 思想,但是我们还是需要引入车身
    private FrameWorkPlus frameWorkPlus;
    public void init() {
        // 同样还是依赖 frameworkplus:init()
    }
    public static void main(String[] args) {

    }
}

FrameWorkPlus :

package newcar;

public class FrameWorkPlus {
    public void init() {
        System.out.println("车身安装");
    }
}

BottomPlus :

package newcar;

public class BottomPlus {
    public void init() {
        System.out.println("底盘安装");
    }
}

TirePlus :

package newcar;

public class TirePlus {
    private int size = 17;

    public void init() {
        System.out.println("轮胎安装");
    }
}

那么我们来看一下 IoC 怎么改
CarPlus :

package newcar;

public class CarPlus {
    private FrameWorkPlus frameWorkPlus;

    // 不用自己制作了
    // 直接用传过来的
    public CarPlus(FrameWorkPlus frameWorkPlus) {
        this.frameWorkPlus = frameWorkPlus;//不在当前类 Car 里面自己创建了,改成别人创建了
    }

    public void init() {
        // 同样还是依赖 frameworkplus:init()
        System.out.println("安装汽车");
        frameworkplus.init();
    }

    public static void main(String[] args) {

    }
}

FrameWorkPlus :

package newcar;

public class FrameWorkPlus {
    private BottomPlus bottomPlus;//我们还是需要底盘的
    
    // 我们不会再自己去创建了,而是直接用传过来的(直接用买过来的)
    // 这样 FrameWorkPlus 就不会受到 bottomPlus 的影响了
    public FrameWorkPlus(BottomPlus bottomPlus) {
        this.bottomPlus = bottomPlus;
    }
    
    public void init() {
        System.out.println("车身安装");
        bottomPlus.init();
    }
}

BottomPlus :

package newcar;

public class BottomPlus {
    private TirePlus tirePlus;
    
    public BottomPlus(TirePlus tirePlus) {
        this.tirePlus = tirePlus;
    }
    public void init() {
        System.out.println("底盘安装");
        tirePlus.init();
    }
}

TirePlus :

package newcar;

public class TirePlus {
    private int size = 17;
    
    public TirePlus(int size) {
        this.size = size;
    }

    public void init() {
        System.out.println("轮胎安装");
    }
}

接下来我们就可以进行程序调用了
JavaEE 突击 2 - Spring 核心与设计思想_第3张图片

package newcar;

public class CarPlus {
    private FrameWorkPlus frameWorkPlus;

    public CarPlus(FrameWorkPlus frameWorkPlus) {
        // 不用自己创造了
        // 直接用传过来的
        this.frameWorkPlus = frameWorkPlus;//不在当前类 Car 里面自己创建了 , 改成别人创建了
    }

    public void init() {
        // 同样还是依赖 frameworkplus:init()
        System.out.println("安装汽车");
        frameWorkPlus.init();
    }

    public static void main(String[] args) {
        // 程序调用
        int size = 15;
        TirePlus tirePlus = new TirePlus(size);
        BottomPlus bottomPlus = new BottomPlus(tirePlus);
        FrameWorkPlus frameWorkPlus = new FrameWorkPlus(bottomPlus);
        CarPlus carPlus = new CarPlus(frameWorkPlus);
        carPlus.init();
    }
}

运行一下 :
JavaEE 突击 2 - Spring 核心与设计思想_第4张图片

那么这里有一个问题 , 我们传统的方式是 new 对象 , 那么这个 IoC 不还是在 new 对象吗 ?
注意 , 这个 main 方法是测试方法 , 和这个 CarPlus 没有任何关系 , 我们可以把这个 main 方法移到其他位置

package newcar;

public class App {
    public static void main(String[] args) {
        // 程序调用
        int size = 15;
        TirePlus tirePlus = new TirePlus(size);
        BottomPlus bottomPlus = new BottomPlus(tirePlus);
        FrameWorkPlus frameWorkPlus = new FrameWorkPlus(bottomPlus);
        CarPlus carPlus = new CarPlus(frameWorkPlus);
        carPlus.init();
    }
}

我们关注的是 App 以外的程序 , App 以外的程序我们并没有进行 new 操作 , 这就相当于把控制权交给了 App , 而不是 CarPlus 类本身
那么我们假如要增加一个属性呢 ? 这也变得非常简单了

package newcar;

public class TirePlus {
    private int size = 17;
    private String color = "黑色";//新增加的属性

    // 我们只需要在构造方法里面多加一个属性即可
    public TirePlus(int size,String color) {
        this.size = size;
        this.color = color;
    }

    public void init() {
        System.out.println("轮胎安装");
    }
}

JavaEE 突击 2 - Spring 核心与设计思想_第5张图片

我们看一下报错的位置
JavaEE 突击 2 - Spring 核心与设计思想_第6张图片

package newcar;

public class App {
    public static void main(String[] args) {
        // 程序调用
        int size = 15;
        String color = "红色";
        TirePlus tirePlus = new TirePlus(size,color);
        BottomPlus bottomPlus = new BottomPlus(tirePlus);
        FrameWorkPlus frameWorkPlus = new FrameWorkPlus(bottomPlus);
        CarPlus carPlus = new CarPlus(frameWorkPlus);
        carPlus.init();
    }
}

所以如果我们增加了一个属性 , 那么另外三个类是一点变化都没有的 , 这样的好处就是你无论怎么修改 , 我们的上层类都受不到影响 , 仍然可以正常实现程序 , 这就是控制反转的好处

1.2.3 对比

JavaEE 突击 2 - Spring 核心与设计思想_第7张图片
在传统的代码中对象创建顺序是:Car -> Framework -> Bottom -> Tire
改进之后解耦的代码的对象创建顺序是:Tire -> Bottom -> Framework -> Car
这其实就是 控制反转
使用 IoC 思想 , 就减少了代码的耦合度(实现了代码的解耦)

1.3 Spring 的 IoC

我们在最刚开始就讲 : Spring 是包含了众多工具方法的 IoC 容器 , 再进一步说 , Spring 是一个包含了众多工具方法的 控制反转 的容器 , 那么控制反转我们分析过了 , 那么再来看一下在 Spring 中 容器 是怎么回事 .
如果 Spring 是容器 , 那么它就具备两个最基础的功能

  1. 将对象存入到容器
  2. 从容器中取出对象

那么学习 Spring , 我们要考虑两件事 :

  1. 如何将对象存入到 Spring 里面
  2. 怎么从 Spring 里面获取对象

那么我们把对象存储到容器里面有什么好处呢 ?
把对象存入到 Spring 里面 , 就代表该对象的生命周期不由当前类控制了 , 把该对象的生死决定权从当前类交给 Spring 里面了 , 需要的时候直接去取 , 不用反复 new 了 .
举个栗子 :
我们农民在干活的时候 , 会需要农具 . Spring 的作用就是仓库 , 存放各种工具 , 但是如果没有 Spring 的话 , 就需要用一次去买一次 , 然后没地方放就扔了 , 这样会十分影响效率
总结 : Spring 是⼀个 IoC 容器,说的是对象的创建和销毁的权利都交给 Spring 来管理了,它本身又具备了存储对象和获取对象的能力。

1.4 DI

提到 IoC , 就需要提到 DI , 因为他们俩是一对 CP
DI 的全程是 Dependency Injection , 翻译成中文就是 依赖注入
我们之前也见过 Dependency 这个词 , 学习 Tomcat 的时候 , 我们需要配置 pom.xml , 里面的依赖就是这个
JavaEE 突击 2 - Spring 核心与设计思想_第8张图片
所谓依赖注入,就是由 IoC 容器在运行期间,动态地将某种依赖关系注入到对象之中。
这么说还不太懂 , 那我这么说 : 将依赖的类 , 加入到当前类中 , 这个就叫做依赖注入
还不太懂 ? 看刚才的例子
JavaEE 突击 2 - Spring 核心与设计思想_第9张图片
依赖注入(DI)和 控制反转(IoC)是从不同的角度的描述的同⼀件事情,就是指通过引入 IoC 容器,利用依赖关系注入的方式,实现对象之间的解耦。
他们俩的目的都是为了解耦合 , 只不过控制反转相当于是一种思路 , 而依赖注入是一种具体实现 .
类比一下 : 控制反转相当于今晚吃什么 ? 只是一个大概的轮廓
而依赖注入就是我今天晚上吃烧烤 , 是一种具体的策略

你可能感兴趣的:(JavaEE,进阶,java-ee,spring,java)