带你了解什么是Spring Ioc

简介: 你好看官,里面请!今天笔者讲的是Spring Ioc。不懂或者觉得我写的有问题可以在评论区留言,我看到会及时回复。 注意:本文仅用于学习参考,不可用于商业用途,如需转载请跟我联系。

1. 什么是 IoC

如果觉得写的还可以,点个赞支持一下笔者呗!你的点赞和关注会让我更快更新哦。笔者会持续更新关于Java和大数据有关的文章。目前集中精力在更新java框架的内容。


了解 Spring 的人肯定都听说过 IoC,那么究竟什么是 IoC 呢?我们先来看一下 IoC 的概念。

IoC(全称 Inversion of Control,中文意思为控制反转),是面向对象编程中的一种设计原则,可以降低代码的耦合性。例如在对象 A 被创建时,通过控制反转,由对象 A 所属的外界实体将 A 所依赖的其他对象的引用传递给 A。

这并不是什么官方的定义,是我根据维基百科中的描述,尽可能的将其概括的容易理解的样子。控制反转是一种编程思想,最常见的实现方式叫做依赖注入(Dependency Injection,简称 DI ),还有一种方式叫 “依赖查找”(Dependency Lookup,简称 DL)。

2. 缘起

2001 年,那是一个春天,有一位老人,啊呸!有一位小伙(没错,那时候还是小伙,头发还很茂盛)使控制反转实现方式之一的依赖注入(DI)一词得到普及。而后,又在 2004 年他又对 “究竟是对哪些方面的控制进行了反转” 的问题进行了进一步的总结。最后得出结论 —— 依赖对象的获得被反转了。

这位小伙就是马丁・福勒(Martin Fowler),那么他是何许人也呢?不用过多的言语来介绍他,你只需要知道他曾经写过一本书叫《Refactoring》就行了,这本书翻译过来叫《重构》,OK,可以开始膜拜了。

3. 改变

我们都知道,Class A 代表 A 是一个类,而 A a = new A() 代表创建一个 A 类型的对象 a。在没有控制反转的时候,在类 A 中使用类 B 的对象 b 时,需要在 A 中 new 一个 b 对象。如果我们使用控制反转的话,只需要在类 A 中声明一个私有的 b 对象,即 private B b。然后创建(new)b 对象的工作交由容器来完成,容器根据注解或者配置文件将 b 注入到 A 的实例中即可。这样带来的好处是巨大的,大大降低了代码的耦合度,如果通过以上描述你不能很清晰的感觉到这种变化(事实上很难通过单纯的文字描述感受到),那么继续看我们接下来的代码实例。

4. 实现方式

在开头介绍什么是 IoC 的时候,我们就提到了,它的实现方式主要有两种,一种是依赖查找,另一种是依赖注入。两者的主要区别在于查找是主动行为,而注入则是被动行为。依赖查找会主动寻找对象所需的依赖,获取依赖对象的时机也是可以自行控制的;依赖注入则是被动的等待容器为其注入依赖对象,容器通过类型或者名称将被依赖对象注入到相应的对象中去。

4.1 依赖查找

依赖查找是主动获取,在需要的时候通过调用框架提供的方法来获取对象,获取时需要提供相关的配置文件路径、key 等信息来确定获取对象的状态。当年显赫一时的 EJB 就是使用依赖查找实现的控制反转。建立在 JavaEE 的 JNDI 规范之上,但随着 EJB 的衰落,依赖查找的实现方式也慢慢无人问津。

4.2 依赖注入

依赖注入是控制反转最常见的实现方式,这在很大程度上得益于 Spring 在 Java 领域的垄断地位。在 Spring 中使用依赖注入可以通过如下四种方式:

  1. 基于接口
  2. 基于 Set 方法
  3. 基于构造函数
  4. 基于注解

由于注解的方便好用,目前几乎所有系统都会使用注解的方式来完成依赖注入。其实使用注解的依赖注入方式我们已经很熟悉了,在之前的小节中我们已经用过 N 多次了。使用 @Controller、@Service、@Component 等注解将类标记为可依赖,然后使用 @Autowire 注解来注入依赖对象。

5. 上代码

Talk is cheap,show me the code. 上面说了那么多,要想真真切切的感受一下控制反转思想相对于传统方式有哪些不同,还得通过实实在在的代码才行。走起!

故事的主人公叫小明,他有一个技能叫做 —— 出去浪。下面我们用代码来实现一下。

5.1 传统方式

创建一个 Person 类,它有一个方法 hangOut (),再创建一个 Bike 类作为交通工具。

public class Person {
    public void hangOut() {
        Bike bike = new Bike();
        bike.drive();
    }
}
@Slf4j
public class Bike {
    public void drive() {
        log.info("骑着自行车出去浪~");
    }
}
@Test
public void test() {
    Person xiaoming = new Person();
    xiaoming.hangOut();
}

小明刚刚大学毕业,一穷二白,虽然很喜欢出去玩,但是只能骑个共享单车,不过倒也悠哉。

经过不断的学习和努力,几年后小明收入越来越高,终于有了一辆属于自己的车,于是以后出去浪就可以开车了。

public class Person {
    public void hangOut() {
//        Bike bike = new Bike();
//        bike.drive();
        Car car = new Car();
        car.drive();
    }
}

小明终于可以开车来一场说走就走的自驾游啦,快哉!

再后来,小明不满足可以自驾游的短途旅行,喜欢上了诗和远方,于是小明出游的交通工具变成了火车。

public class Person {
    public void hangOut() {
//        Bike bike = new Bike();
//        bike.drive();
//        Car car = new Car();
//        car.drive();
        Train train = new Train();
        train.drive();
    }
}

买张火车票就可以游历祖国的大好河山,美哉!

没过多久,小明游遍了国内的美景,开始向往异国风情,于是开启了飞行之旅。

public class Person {
    public void hangOut() {
//        Bike bike = new Bike();
//        bike.drive();
//        Car car = new Car();
//        car.drive();
//        Train train = new Train();
//        train.drive();
        AirPlane airPlane = new AirPlane();
        airPlane.drive();
    }
}

感受异域文化,体味不同的风土人情,妙哉!

你知道的,没过多久,小明又厌倦了陆地,于是他的心又飘向了海洋。

public class Person {
    public void hangOut() {
//        Bike bike = new Bike();
//        bike.drive();
//        Car car = new Car();
//        car.drive();
//        Train train = new Train();
//        train.drive();
//        AirPlane airPlane = new AirPlane();
//        airPlane.drive();
    Ship ship = new Ship();
        ship.drive();
  }
}

乘风破浪,感受无边的海洋,壮哉!

虽然出去玩可以悠哉、快哉、美哉、妙哉甚至壮哉。但是我们发现,每换一个交通工具,就需要对 Person 类进行修改,实在是麻烦,而且非常不友好,接下来我们看看使用控制反转会发生什么。

5.2 控制反转

改造 Person 类:

@AllArgsConstructor
public class Person {
    private Driveable driveable;
    public void hangOut() {
        driveable.drive();
    }
}

我们将交通工具从 hangOut 方法中提取出来变成 Person 的私有成员变量,并且将其抽象为一个 Driveable 接口。然后让所有的交通工具都实现这个接口。

然后当小明出去浪的时候,再指定乘坐哪种交通工具:

// Bean 容器
private Map<String, Object> container = new HashMap<>();
/**
 * 模拟 Spring 容器初始化
 */
@Before
public void init() {
    Driveable bike = new Bike();
    container.put("bike", bike);
    Driveable car = new Car();
    container.put("car", car);
    Driveable train = new Train();
    container.put("train", train);
    Driveable airPlane = new AirPlane();
    container.put("airPlane", airPlane);
    Driveable ship = new Ship();
    container.put("ship", ship);
}
/**
 * 获取 Bean
 * @param name
 * @return
 */
public Object getBean(String name) {
    return container.get(name);
}
@Test
public void test() {
    Driveable bike = (Driveable) container.get("bike");
    Person xiaoming = new Person(bike);
    xiaoming.hangOut();
    Driveable car = (Driveable) container.get("car");
    xiaoming = new Person(car);
    xiaoming.hangOut();
    Driveable train = (Driveable) container.get("train");
    xiaoming = new Person(train);
    xiaoming.hangOut();
    Driveable airPlane = (Driveable) container.get("airPlane");
    xiaoming = new Person(airPlane);
    xiaoming.hangOut();
    Driveable ship = (Driveable) container.get("ship");
    xiaoming = new Person(ship);
    xiaoming.hangOut();
}

由上面代码可以看出,小明可以在不同交通工具之间随意切换,而无需再修改 Person 类,只需要在出去浪之前指定相应的交通工具即可。小明只需要关心 “要不要出去浪” 这一点即可,不需要操心到底是怎么去。这一点,采用传统方式根本无法做到。

相关文章
|
10天前
|
XML Java 数据格式
【SpringFramework】Spring IoC-基于XML的实现
本文主要讲解SpringFramework中IoC和DI相关概念,及基于XML的实现方式。
99 69
|
9天前
|
Java Spring 容器
【SpringFramework】Spring IoC-基于注解的实现
本文主要记录基于Spring注解实现IoC容器和DI相关知识。
42 21
|
15天前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
14天前
|
存储 Java 应用服务中间件
【Spring】IoC和DI,控制反转,Bean对象的获取方式
IoC,DI,控制反转容器,Bean的基本常识,类注解@Controller,获取Bean对象的常用三种方式
|
5月前
|
XML Java 数据格式
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
这篇文章是Spring5框架的实战教程,主要介绍了如何在Spring的IOC容器中通过XML配置方式使用外部属性文件来管理Bean,特别是数据库连接池的配置。文章详细讲解了创建属性文件、引入属性文件到Spring配置、以及如何使用属性占位符来引用属性文件中的值。
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
|
1月前
|
存储 缓存 Java
Spring面试必问:手写Spring IoC 循环依赖底层源码剖析
在Spring框架中,IoC(Inversion of Control,控制反转)是一个核心概念,它允许容器管理对象的生命周期和依赖关系。然而,在实际应用中,我们可能会遇到对象间的循环依赖问题。本文将深入探讨Spring如何解决IoC中的循环依赖问题,并通过手写源码的方式,让你对其底层原理有一个全新的认识。
57 2
|
2月前
|
XML 缓存 Java
搞透 IOC、Spring IOC ,看这篇就够了!
本文详细解析了Spring框架的核心内容——IOC(控制反转)及其依赖注入(DI)的实现原理,帮助读者理解如何通过IOC实现组件解耦,提高程序的灵活性和可维护性。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
|
4月前
|
XML Java 数据格式
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
Spring 第二节内容补充 关于Bean配置的更多内容和细节 万字详解!
300 18
|
4月前
|
XML Java 测试技术
spring复习01,IOC的思想和第一个spring程序helloWorld
Spring框架中IOC(控制反转)的思想和实现,通过一个简单的例子展示了如何通过IOC容器管理对象依赖,从而提高代码的灵活性和可维护性。
spring复习01,IOC的思想和第一个spring程序helloWorld
|
2月前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
48 0
下一篇
开通oss服务