自学内容网 自学内容网

四、Spring初识IoC和DI

一、初识IoC和DI

1.1Spring是什么?

我们知道了Spring是⼀个开源框架,他让我们的开发更加简单.他⽀持⼴泛的应⽤场 景,有着活跃⽽庞⼤的社区,这也是Spring能够⻓久不衰的原因. 但是这个概念相对来说,还是⽐较抽象. 我们⽤⼀句更具体的话来概括Spring,那就是:Spring是包含了众多⼯具⽅法的IoC容器

1.1.1 容器

容器是⽤来容纳某种物品的(基本)装置。⸺来⾃:百度百科 ⽣活中的⽔杯,垃圾桶,冰箱等等这些都是容器.

在比如:

List/Map->数据存储容器
Tomcat->Web容器

1.1.2 IoC是什么

在类上⾯添加 @RestController 和 @Controller 注解,就是把这个对象交给Spring管理,Spring框架启动时就会加载该类.把对象交 给Spring管理,就是IoC思想

IoC: Inversion of Control (控制反转),也就是说Spring是⼀个"控制反转"的容器

控制反转是什么?----->  当需要某个对象时,传统开发模式中需要⾃⼰通过new创建对象,现在不需要再进⾏创建, 把创建对象的任务交给容器, 程序中只需要依赖注⼊(DependencyInjection,DI)就可以了. 这个容器称为:IoC容器. Spring是⼀个IoC容器,所以有时Spring也称为Spring容器. 

举个生活中的例子:

想象你每天早上都需要一杯咖啡。通常情况下,你自己去厨房找咖啡机和咖啡豆来做咖啡。但在控制反转的情况下,你的家人已经知道你喜欢喝咖啡,并且在你起床前就把泡好的咖啡放在桌上等你。这里,你不再需要自己去找资源(咖啡机和咖啡豆),而是这些资源被“注入”给了你。这就像是依赖注入,外部环境(你的家人)负责准备并提供你需要的东西这种方式让早晨的流程变得更简单、直接,也更灵活,因为你不需要关心咖啡的准备工作了。这就是控制反转的基本思想:将对象的创建和管理从对象自身转移到外部环境。

1.2 IoC的介绍

1.2.1 传统的程序开发

需求:造一辆车

先设计轮⼦(Tire),然后根据轮⼦的⼤⼩设计底盘(Bottom),接着根据底盘设计⻋⾝(Framework),最 后根据⻋⾝设计好整个汽⻋(Car)。这⾥就出现了⼀个"依赖"关系:汽⻋依赖⻋⾝,⻋⾝依赖底盘,底 盘依赖轮⼦.

代码实现:

import org.w3c.dom.ls.LSOutput;

//TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or
// click the <icon src="AllIcons.Actions.Execute"/> icon in the gutter.
public class Main {
    public static void main(String[] args) {
        Car car = new Car();
    }
}

//汽车类
class Car {
    private Tramework tramework;

    public Car() {
        tramework = new Tramework();
        System.out.println("Car init...");
    }
}


//车身类
class Tramework {
    private Bottom bottom;

    public Tramework() {
        bottom = new Bottom();
        System.out.println("Tramework init...");
    }
}

//地盘类
class Bottom {
    private Tire tire;

    public Bottom() {
        tire = new Tire();
        System.out.println("Bottom init...");
    }
}

//轮胎类
class Tire {
    private int size;

    public Tire() {
        this.size = 17;
        System.out.println("Tire size : " + this.size);
    }
}

当我们要去添加轮胎类的Tire构造方法的形参编译时会出现一层一层的关联报错!

通过上述案例会发现这样的设计 代码可维护型很低,程序的耦合度⾮常⾼(修改⼀处代码,影响其他处的代码修改).

1.2.2 解决方案

尝试换⼀种思路,我们先设计汽⻋的⼤概样⼦,然后根据汽⻋的样⼦来设计⻋⾝,根据⻋⾝来设计 底盘,最后根据底盘来设计轮⼦.这时候,依赖关系就倒置过来了:轮⼦依赖底盘,底盘依赖⻋⾝, ⻋⾝依赖汽⻋。

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

public class Main {
    public static void main(String[] args) {
        Tire tire = new Tire(17);
        Bottom bottom = new Bottom(tire);
        Framework framework = new Framework(bottom);
        Car car = new Car(framework);
    }
}

//汽车类
class Car {
    private Framework tramework;

    public Car(Framework framework) {
        this.tramework = framework;
        System.out.println("Car init...");
    }
}


//车身类
class Framework {
    private Bottom bottom;

    public Framework(Bottom bottom) {
        this.bottom = bottom;
        System.out.println("Tramework init...");
    }
}

//地盘类
class Bottom {
    private Tire tire;

    public Bottom(Tire tire) {
        this.tire = tire;
        System.out.println("Bottom init...");
    }
}

//轮胎类
class Tire {
    private int size;

    public Tire(int size) {
        this.size = size;
        System.out.println("Tire size : " + this.size);
    }
}

代码经过以上调整,⽆论底层类如何变化,整个调⽤链是不⽤做任何改变的,这样就完成了代码之间 的解耦,从⽽实现了更加灵活、通⽤的程序设计了。

1.2.3 IoC的优点

在传统的代码中对象创建顺序是:Car->Framework->Bottom->Tire
改进之后解耦的代码的对象创建顺序是:Tire->Bottom->Framework->Car

我们发现了⼀个规律,通⽤程序的实现代码,类的创建顺序是反的,传统代码是Car控制并创建了 Framework,Framework创建并创建了Bottom,依次往下,⽽改进之后的控制权发⽣的反转,不再是使⽤⽅对象创建并控制依赖对象了,⽽是把依赖对象注⼊将当前对象中,依赖对象的控制权不再由当前类控制了. 这样的话,即使依赖类发⽣任何改变,当前类都是不受影响的,这就是典型的控制反转,也就是IoC的 实现思想。

从上⾯也可以看出来,IoC容器具备以下优点:

1、资源不由使⽤资源的双⽅管理,⽽由不使⽤资源的第三⽅管理,这可以带来很多好处。第⼀,资源集 中管理,实现资源的可配置和易管理。

2、降低了使⽤资源双⽅的依赖程度,也就是我们说的耦合度。

3、资源集中管理: IoC容器会帮我们管理⼀些资源(对象等),我们需要使⽤时,只需要从IoC容器中            去取就可以了。

4、我们在创建实例的时候不需要了解其中的细节,降低了使⽤资源双⽅的依赖程度,也就是耦合            度。

1.3 DI 介绍

DI: DependencyInjection(依赖注⼊) 容器在运⾏期间,动态的为应⽤程序提供运⾏时所依赖的资源,称之为依赖注⼊

依赖注⼊(DI)和控制反转(IoC)是从不同的⻆度的描述的同⼀件事情,依赖注⼊是从应⽤程序的⻆度来描述,就是指通过引⼊IoC容器,利⽤依赖关系注⼊的⽅式,实现对象之间的解耦.

上述代码中,是通过构造函数的⽅式,把依赖对象注⼊到需要使⽤的对象中的

 IoC 是⼀种思想,也是"⽬标",⽽思想只是⼀种指导原则,最终还是要有可⾏的落地⽅案,⽽DI就属于 具体的实现。所以也可以说,DI是IoC的⼀种实现.

⽐如说我今天⼼情⽐较好,吃⼀顿好的犒劳犒劳⾃⼰,那么"吃⼀顿好的"是思想和⽬标(是 IoC),但最后我是吃海底捞还是杨国福?这就是具体的实现,就是DI。

二. IoC &DI使用

既然Spring是⼀个IoC(控制反转)容器,作为容器,那么它就具备两个最基础的功能:

• 存

• 取

Spring 容器管理的主要是对象,这些对象,我们称之为"Bean".我们把这些对象交由Spring管理,由 Spring来负责对象的创建和销毁.我们程序只需要告诉Spring,哪些需要存,以及如何从Spring中取出 对象

⽬标:把BookDao,BookService交给Spring管理,完成Controller层,Service层,Dao层的解耦

步骤:

1. Service层及Dao层的实现类,交给Spring管理: 使⽤注解: @Component

2. 在Controller层和Service层注⼊运⾏时依赖的对象:使⽤注解 @Autowired

实现:

1. 把BookDao交给Spring管理,由Spring来管理对象

package com.example.book.dao;

import com.example.book.model.BookInfo;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

@Component
public class BookDao {
    public List<BookInfo> mockData() {
        //对于已知的数据量 建议初始化容量
        List<BookInfo> bookInfos = new ArrayList<>(15);
        for (int i = 1; i <= 15; i++) {
            BookInfo bookInfo = new BookInfo();
            bookInfo.setId(1);
            bookInfo.setBookName("图书" + i);
            bookInfo.setAuthor("作者" + i);
            bookInfo.setCount(new Random().nextInt(200));
            bookInfo.setPrice(new BigDecimal(new Random().nextInt(100)));
            bookInfo.setPublish("出版社" + i);
            bookInfo.setStatus(i % 5 == 0 ? 0 : 1);
            bookInfos.add(bookInfo);
        }
        return bookInfos;
    }
}

2.把BookService交给Spring管理,由Spring来管理对象

package com.example.book.service;

import com.example.book.dao.BookDao;
import com.example.book.model.BookInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class BookService {

     @Autowired
     private BookDao bookDao;
    public List<BookInfo> getBookList() {
        //1、获取图书数据
        //2、对图书的数据进行处理
        //3、返回数据
        //mock 表示虚拟假数据
        List<BookInfo> bookInfos =bookDao.mockData();
        for (BookInfo bookInfo : bookInfos) {
            if (bookInfo.getStatus() == 1) {
                bookInfo.setStatusCN("可借阅");
            } else {
                bookInfo.setStatusCN("不可借阅");
            }
        }
        return bookInfos;
    }
}

3.删除创建BookDao的代码,从Spring中获取对象

package com.example.book.service;

import com.example.book.dao.BookDao;
import com.example.book.model.BookInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class BookService {

     @Autowired
     private BookDao bookDao;
    public List<BookInfo> getBookList() {
        //1、获取图书数据
        //2、对图书的数据进行处理
        //3、返回数据
        //mock 表示虚拟假数据
        List<BookInfo> bookInfos =bookDao.mockData();
        for (BookInfo bookInfo : bookInfos) {
            if (bookInfo.getStatus() == 1) {
                bookInfo.setStatusCN("可借阅");
            } else {
                bookInfo.setStatusCN("不可借阅");
            }
        }
        return bookInfos;
    }
}

4. 删除创建BookService的代码,从Spring中获取对象

package com.example.book.controller;

import com.example.book.model.BookInfo;
import com.example.book.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/book")
public class BookController {
    @Autowired
    BookService bookService ;

    @RequestMapping("/getBookList")
    public List<BookInfo> getBookList() {

        return bookService.getBookList();
    }
}


原文地址:https://blog.csdn.net/m0_63272315/article/details/145263956

免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!