【Spring篇】初识 Spring IoC 与 DI

目录

一.  Spring 是什么 ?

二. 何为 IoC ? 

三. 如何理解 Spring IoC ?

四. IoC 与 DI

五 . 总结


一.  Spring 是什么 ?

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

  • 以下是 Spring 框架的一些核心特点:
  1. 轻量级:Spring 框架采用了松耦合的设计原则,仅依赖于少量的第三方库,因此它是一个轻量级的框架。开发人员可以根据需要选择使用 Spring 的特定功能,而无需引入整个框架。
  2. 控制反转(IoC):Spring 框架通过控制反转(IoC)容器管理应用程序中的对象及其依赖关系。通过 IoC 容器,开发人员可以将对象的创建、组装和生命周期管理交给 Spring 框架处理,从而实现了松耦合和可测试性。
  3. 面向切面编程(AOP):Spring 框架支持面向切面编程,可以通过 AOP 在应用程序中实现横切关注点的模块化。例如,日志记录、事务管理和安全性等横切关注点可以通过 AOP 进行集中处理,而不会侵入业务逻辑的代码。
  4. 声明式事务管理:Spring 框架提供了声明式事务管理的支持。通过使用注解或 XML 配置,开发人员可以将事务管理逻辑与业务逻辑分离,并且可以轻松地在方法或类级别上应用事务。
  5. 框架整合:Spring 框架可以与许多其他开源框架和技术无缝集成,如 Hibernate、MyBatis、JPA、Struts 和 JSF 等。这使得开发人员可以使用 Spring 框架来整合和协调不同的技术,构建全面的企业应用程序。
  6. 测试支持:Spring 框架提供了广泛的测试支持,包括单元测试和集成测试。它提供了一个专门的测试上下文,可以轻松地编写和执行单元测试,以验证应用程序的行为和功能

如果要使用一句话来概括 Spring , 那就是 Spring是包含了众多工具方法的 IoC 容器 

何为 IoC ? ,  IoC 的全称叫做 Inversion of Control , 即为控制反转 ,也就是说 Spring 是一个控制反转的容器 , 那么怎样理解上述的内容呢 ?

二. 何为 IoC ? 

准确来说 , IoC 指的并不是一种具体的技术, 而是一个实现对象解耦的思想 

耦合 : 当两个或者两个以上的对象存在依赖,一方修改之后就会影响另外一方,就说明这两个对象之间存在这耦合关系 , 而解耦, 就是为了解除这两个对象之间的依赖关系。

那么 IoC 是如何实现对象的解耦呢 ? 

下面通过一个具体的示例来进行讲解 :
       在传统的开发思想中 , 当我们要构建一辆车时 , 而车又依赖于车身, 车身又依赖于底盘,底盘又依赖于轮胎,他们之间的依赖关系如下图所示 :

 当我们使用代码进行实现时 ,所有类之间的调用链如下所示:

// Car类
public class Car {
    // car 进行初始化时 , 需要调用 framework
    public void init(){
        System.out.println("do car");
        Framework framework = new Framework();
        framework.init();
    }
    public static void main(String[] args){
        Car car = new Car();
        car.init();
    }
}
// Framework类
public class Framework {
    // framework 进行初始化时, 调用了Bottom
    public void init(){
        System.out.println("do framework");
        Bottom bottom = new Bottom();
        bottom.init();
    }

}
// Bottom 类
public class Bottom{
    // Bottom 进行初始化时,调用了 Tire
    public void init(){
        System.out.println("do bottom");
        Tire tire = new Tire();
        tire.init();
    }
}
// Tire 类
public class Tire {
    private int size = 10;
    public void init(){
        System.out.println("size -> "+size);
    }
}

在上述的代码当中,如果轮胎的尺寸 size 发生了改变,相对应的 底盘,车身,再到整车都要发生一定的变化,也就是当我们在自身类创建下级类时,当下级类发生改变操作,自己也要跟着修改,代码的耦合程度较高,不利于后续的更新和添加元素,所以如何实现程序的解耦呢?

那么如何解决传统开发中的缺陷呢 ?

答案是我们在创建类时,不在每个类中创建下级类,而是改为传递的方式(也就是注入的方式),因为我们不需要在当前类中创建下级类了,所以下级类中即使发生变化,当前类也无需修改任何代码,这样就完成了程序的解耦。

下面我们将参数传递的方式进行修改:

  • 通过将对象进行传递而并非 new 对象的方式来进行解决:
# car类
public class Car {
    private Framework framework;

    // 将 framework 注入 car
    public Car(Framework framework) {
        this.framework = framework;
    }
    public void init() {
        System.out.println("do car...");
        framework.init();
    }
}
# framework 类
public class Framework {
    private Bottom bottom;
     // bottom 注入 framework
    public Framework(Bottom bottom){
        this.bottom = bottom;
    }

    public void init(){
        System.out.println("do framework");
        bottom.init();
    }
}
# bottom类
public class Bottom {
    private Tire tire;
   // tire 注入 bottom
    public Bottom(Tire tire) {
        this.tire = tire;
    }

    public void init() {
        System.out.println("do bottom...");
        tire.init();
    }
}
# trie 类
package newCar;

public class Tire {
    private int size = 17;
    private String color = "红色";

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

    public void init() {
        System.out.println("size -> " + size + " | color -> " + color);
    }
}
# 测试类
public class Test {
    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.init();
    }
}

代码经过上述的调整之后,无论底层的类如何进行改变,整个调用链都不会发生变化,这样就完成了代码之间的解耦。

 在传统的代码中对象的创建顺序是 : Car -> Framework -> Bottom -> Tire

 改进之后解耦的代码创建顺序是:     Tire -> Bottom -> Framework -> Car

再举一个开发中比较简单的例子 :
当我们在开发过程中, A 对象要使用 B对象的 某个方法, 我们通常的实现方法如下 :

class A{
   public void init(){
    // new一个B类对象,调用 init()方法
     B b = new B();
     b.init();
  }
}
class B{
   public B(){

  }
  public void init(){
    System.out.println("hello world!");
  }
}

此时,A 和 B对象是相互进行耦合的, 当修改了B中构造方法的参数时,A对象也要随之发生改变。

class B {
   public B(String name){
       System.out.println("姓名 :"+name);
  }
  public void init(){
       System.out.println("Hello word!");
  }
}

 那么实际业务中,如何解决上述的问题呢?

与上一个例子类似, 也是通过将对象进行传递(注入)的方式 , 代码如下 :

class A {
    // 先定义一个需要依赖的 B 对象
    private B b;
    // 通过构造方法实现赋值(初始化)
    public A(B b) {
        this.b = b;
    }
    public void init() {
        // 调用 B 类中的 init 方法
        b.init();
    }
}
class B {
    public B(String name) {
        System.out.println("姓名:" + name);
    }
    public void init() {
        System.out.println("Hello World!");
    }
}

这样修改之后,无论B的构造方法怎么修改,而调用他的A类不需要做任何修改 ,这样就实现了对象的解耦,那么对象的解耦 和 IoC 又有什么关系呢?

通过上边的两个例子,究其原因还是控制权反转的问题 ,A对象对于B对象的管理权交出,交给其他程序来管理,此时A对象对于B对象的管理权发生了反转和改变,这就是 IoC 

三. 如何理解 Spring IoC ?

在 Spring 中, 将 对象交给了 IoC 容器来进行管理 , 不需要关注怎么去创建对象,而是关注创建对象之后的操作, 把对象的创建,初始化,销毁交给了 Spring IoC 容器来管理 。

既然 Spring 是一个IoC容器 ,那么他就具有两个最基础的功能 :

  • 将对象存入到容器
  • 从容器中取出对象

也就是说, 对象的创建和销毁都交给了Spring来管理了,它本身又具备了存储对象和获取对象的能力 。

Spring IoC 的优点有哪些 ?

  • 实现对象解耦
  • 使用更加方便(不需要手动去new创建,和关注对象背后的依赖问题,只关注使用权)
  • 更加高效(从容器中取出对象,不需要重新new)

四. IoC 与 DI

DI 是 Dependency Injection 的缩写,翻译成中文是“依赖注入”的意思。依赖注入不是一种设计实现,而是一种具体的技术,它是在 IoC 容器运行期间,动态地将某个依赖对象注入到当前对象的技术就叫做 DI(依赖注入)

在上述的两个例子当中,对象的传递通过构造方法被动的获取对象,在Spring 中 DI 的实现一般通过注解来主动的获取对象, IoC 是一种设计思想,而 DI 是一种具体的实现技术,比如想吃顿好的是一种思想,但是吃火锅还是串串是一种具体的实现。

Spring中DI有三种 常用的注入方式,后边会详细介绍,下面简单介绍演示一下属性注入:

@Service
public class FrameWork{
    @Autowired
    private Bottom bottom;//通过属性注入
}

五 . 总结

     IoC 和 DI 都是 Spring 框架中的重要概念,它们都是用来实现对象解耦的,其中 IoC(控制反转)是一种设计思想,而 DI(依赖注入)是一种具体的实现手段,Spring IoC 中最基础的功能就是对对象的存取。


猜你喜欢

转载自blog.csdn.net/m0_56361048/article/details/131034141