带你了解什么是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 类,只需要在出去浪之前指定相应的交通工具即可。小明只需要关心 “要不要出去浪” 这一点即可,不需要操心到底是怎么去。这一点,采用传统方式根本无法做到。

相关文章
|
5月前
|
XML Java 测试技术
《深入理解Spring》:IoC容器核心原理与实战
Spring IoC通过控制反转与依赖注入实现对象间的解耦,由容器统一管理Bean的生命周期与依赖关系。支持XML、注解和Java配置三种方式,结合作用域、条件化配置与循环依赖处理等机制,提升应用的可维护性与可测试性,是现代Java开发的核心基石。
|
XML Java 测试技术
Spring IOC—基于注解配置和管理Bean 万字详解(通俗易懂)
Spring 第三节 IOC——基于注解配置和管理Bean 万字详解!
888 26
|
9月前
|
XML 人工智能 Java
Spring IOC 到底是什么?
IOC(控制反转)是一种设计思想,主要用于解耦代码,简化依赖管理。其核心是将对象的创建和管理交给容器处理,而非由程序直接硬编码实现。通过IOC,开发者无需手动new对象,而是由框架负责实例化、装配和管理依赖对象。常见应用如Spring框架中的BeanFactory和ApplicationContext,它们实现了依赖注入和动态管理功能,提升了代码的灵活性与可维护性。
230 1
|
10月前
|
XML Java 数据格式
Spring IoC容器的设计与实现
Spring 是一个功能强大且模块化的 Java 开发框架,其核心架构围绕 IoC 容器、AOP、数据访问与集成、Web 层支持等展开。其中,`BeanFactory` 和 `ApplicationContext` 是 Spring 容器的核心组件,分别定位为基础容器和高级容器,前者提供轻量级的 Bean 管理,后者扩展了事件发布、国际化等功能。
262 18
|
XML Java 数据格式
京东一面:spring ioc容器本质是什么? ioc容器启动的步骤有哪些?
京东一面:spring ioc容器本质是什么? ioc容器启动的步骤有哪些?
|
XML Java 数据格式
【SpringFramework】Spring IoC-基于XML的实现
本文主要讲解SpringFramework中IoC和DI相关概念,及基于XML的实现方式。
294 69
|
12月前
|
Java 容器 Spring
什么是Spring IOC 和DI ?
IOC : 控制翻转 , 它把传统上由程序代码直接操控的对象的调用权交给容 器,通过容器来实现对象组件的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转 移,从程序代码本身转移到了外部容器。 DI : 依赖注入,在我们创建对象的过程中,把对象依赖的属性注入到我们的类中。
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
Java Spring 容器
【SpringFramework】Spring IoC-基于注解的实现
本文主要记录基于Spring注解实现IoC容器和DI相关知识。
226 21
|
存储 Java 应用服务中间件
【Spring】IoC和DI,控制反转,Bean对象的获取方式
IoC,DI,控制反转容器,Bean的基本常识,类注解@Controller,获取Bean对象的常用三种方式
538 12

热门文章

最新文章