聊聊Spring中IOC的基本原理

简介: 在我们学习spring和面试的过程中,有一个核心的内容就叫做IOC。IOC(Inversion of Control),中文翻译即“控制反转”,它不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将设计好的对象交给容器控制,而不是传统的在对象内部直接控制。

在我们学习spring和面试的过程中,有一个核心的内容就叫做IOC。IOC(Inversion of Control),中文翻译即“控制反转”,它不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将设计好的对象交给容器控制,而不是传统的在对象内部直接控制。


所以通过以上的介绍,我们或许有这样的疑问:谁控制谁,控制什么,怎么反转,哪些方面反转了?


带着这些疑问,我们来一起学习下Ioc的知识!


1. IOC理论的诞生


前面说到Ioc并不是一种技术,而是一种理论一种设计思想,就跟面向对象一样。在采用面向对象设计思想开发的系统中,它底层的实现是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑。就像一辆汽车,它的运行其实是有很多个独立的器械之间的相互合作来推动的。比如发动机、底盘、离合器、变数器、机箱等等,这些主要的零件又是由各类各样的螺丝、转轮等组成。


就像组成汽车的各个零件对象相互配合,少了谁也不行一样。系统的对象之间的耦合关系即是无法避免的,也是十分必要的,因为这是协同工作的基础。但是随着一些大型系统的规模越来越庞大,对象之间的依赖关系也变得越来越复杂,这就导致出现对象之间的多重依赖性关系。对象之间耦合关系过于复杂的系统,它的设计、迭代也会变得复杂,因为这些对象和系统之前的关系会出现牵一发而动全身的情形。


为了解决对象之间的耦合度过高的问题,软件专家Michael Mattson提出了IOC理论,用来实现对象之间的“解耦”,这个理论已经被成功地应用到实践当中,比如现在很多的项目都采用了IOC设计思想的Spring框架。


2. 什么是IOC


IOC是Inversion of Control的缩写,翻译成中文即“控制反转”。


对于Spring框架来说,就是由Spring来负责控制对象的生命周期和对象间的关系。举个例子,如果我们想吃宫保鸡丁,然后自己做,这时候我们就需要去买食材、然后做饭、吃完饭之后还得处理垃圾、洗碗,这个过程其实是很复杂的,因为我们必须自己设计和面对整个过程。但是如果采用了Ioc的设计思想,我们这时候只需要做一件事事情——去饭店点菜。不论我们想吃宫保鸡丁、水煮肉片、烤鱼还是什么任何其他口味、菜系或者类型的食物,饭店都会按照我们的需求提供给我们,吃完之后我们也不需要处理垃圾(销毁对象)。这个整个的过程都不需要我们自己参与控制,而是通过饭店这样一个类似于容器的来进行控制。


Spring的Ioc设计思想就是这样,所有的类都会在Spring容器中登记,告诉Spring你是个什么东西,需要什么东西,然后Spring就会在系统运行到恰当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西,当你不需要的时候就在销毁。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。也就是借助于“第三方”工具(IOC容器)来实现具有依赖关系的对象之间的解耦,类似于下图:


9bedcbcfc0b54535ab6eb6819cca8869~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg

通过使用中间的IOC容器,使得A、B、C、D这4个对象没有了直接的耦合关系,它们之间的传动全部依靠“第三方”的Ioc容器。


在没有引入IOC容器,对象A依赖于对象B,那么对象A在初始化或者运行到某一点的时候,自己必须主动去创建对象B或者使用已经创建的对象B。无论是创建还是使用对象B,控制权都在自己手上。


引入IOC容器之后,对象A与对象B之间失去了直接联系,所以,当对象A运行到需要对象B的时候,IOC容器会主动创建一个对象B注入到对象A需要的地方。


通过前后的对比,我们不难看出来:对象A获得依赖对象B的过程,由主动行为变为了被动行为,控制权颠倒过来了,这就是“控制反转”这个名称的由来。


全部对象的控制权全部由“第三方”IOC容器进行控制,所以,IOC容器成了整个系统的关键核心,它起到了一种类似“粘合剂”的作用,把系统中的所有对象粘合在一起发挥作用,如果没有IOC容器,对象与对象之间会彼此失去联系。


3. 什么IOC容器


前面说到了控制反转的核心是Ioc容器,那么什么是Ioc容器呢?


Ioc容器就是具有依赖注入功能的容器,Ioc容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。应用程序无需直接在代码中new相关的对象,应用程序由IOC容器进行组装。在Spring IOC容器的代表就是org.springframework.beans包中的BeanFactory接口,BeanFactory接口提供了IOC容器最基本功能;而org.springframework.context包下的ApplicationContext接口扩展了BeanFactory,还提供了与Spring AOP集成、国际化处理、事件传播及提供不同层次的context实现 (如针对web应用的WebApplicationContext)。简单说, BeanFactory提供了IOC容器最基本功能,而 ApplicationContext 则增加了更多支持企业级功能支持。ApplicationContext完全继承BeanFactory,因而BeanFactory所具有的语义也适用于ApplicationContext。


由Ioc容器管理的那些对象一般称之为它Bean, Bean就是由Spring容器初始化、装配及管理的对象,除此之外,bean就与应用程序中的其他对象没有什么区别。


所以Ioc容器实际上就是一个map,里面存的是各种对象,在项目启动的时候会读取配置文件中的bean节点,根据全限定类名使用反射创建对象放到map里,扫描到打上@repository、@service、@controller、@component这些注解的类然后通过使用反射创建对象放到map中。这时候map中就存在各种对象了,后面代码在需要使用到里面的对象的时候,再通过依赖注入(DI)。


4. 依赖注入(DI)


前面说到项目启动的一开始通过读取配置文件将对象全部存放到ioc容器中,然后再在合适的时机进行依赖注入。我们知道控制反转就是将获得依赖对象的控制权交给了ioc容器。也就是说反转的具体就是获得依赖对象的过程。


控制被反转之后,获得依赖对象的过程就由本来的自动生成变为了交给IOC容器来主动注入。所以控制反转的另一个名字叫做依赖注入(DI,Dependency Injection)。所谓依赖注入,就是由IOC容器在运行期间,动态地将某种依赖关系注入到对象之中,依赖注入也就是实现Ioc的方法。


所以,依赖注入(DI)和控制反转(IOC)是从不同的角度的描述的同一件事情,就是指通过引入IOC容器,利用依赖关系注入的方式,实现对象之间的解耦。


比如对象A依赖于对象B,当对象A需要用到对象B的时候,IOC容器就会立即创建一个对象B送给对象A。IOC容器就是一个对象制造工厂(BeanFactory),需要什么,就会给你送去什么,然后直接使用就可以了,而再也不用去关心你所用的东西是如何制成的,也不用关心最后是怎么被销毁的,这一切全部由IOC容器包办,这也是工厂方法设计模式的思想了。Ioc就是典型的工厂模式,通过sessionfactory去注入实例。


5. 举一个小栗子


前面介绍了这么多,接下来看一个简单的例子。


创建一个spring项目,工程结构如下图所示:


3d96e3375b58494cb00fe5eee00c5e22~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


首先创建一个helloservice接口,然后创建一个其实现类,代码分别如下:


public interface HelloService {
    public void say();
}
复制代码
public class HelloServiceImp implements HelloService {
    public void say(){
        System.out.println("Hello World");
    }
}
复制代码


接口和其实现类以及方法都开发好了,那如何使用Spring IOC容器来管理它们呢?这就需要配置文件,让IOC容器知道要管理哪些对象。创建一个配置文件helloworld.xml:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    <!-- id 表示组件的名字,class表示组件类 -->
    <bean id="helloService" class="com.jiang.HelloServiceImp" />
</beans>
复制代码


最后我们就需要获取IOC容器并实现功能。


首先应该实例化一个IOC容器,然后从容器中获取需要的对象,然后调用接口完成我们需要的功能,创建一个测试代码代码示例如下:


package com.jiang;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestHello {
    @Test
    public void test(){
        // 1、读取配置文件实例化一个IOC容器
        ApplicationContext context = new ClassPathXmlApplicationContext("helloword.xml");
        // 2、从容器中获取Bean,注意此处完全“面向接口编程,而不是面向实现”
        HelloService helloService = context.getBean("helloService",HelloService.class);
        // 3、执行业务逻辑
        helloService.say();
    }
}
复制代码


输出结果如下:


b598dcf9d41a4237a391c0fe1ebb9c4e~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp (1).jpg

6、总结


以上就是我对于ioc的理解。ioc的思想最核心的地方在于,资源不由使用资源的双方管理,而由不使用资源的第三方管理,这可以带来很多好处。第一,资源集中管理,实现资源的可配置和易管理。第二,降低了使用资源双方的依赖程度,也就是耦合度。这样就提高系统的可维护性,而且非常便于进行单元测试。并且各个组件之间的依赖性降低了,就提高了系统的可重复性和可拓展性


ioc中有两个核心的可以理解为技术点的就是工厂设计模式以及反射。IOC容器的工作模式看做是工厂模式的升华,可以把IOC容器看作是一个工厂,这个工厂里要生产的对象都在配置文件中给出定义,然后利用反射,根据配置文件中给出的类名生成相应的对象。


如果你觉得本文不错,就点赞分享给更多的人吧!


如果你觉得文章有不足之处,或者更多的想法和理解,欢迎指出讨论!

目录
相关文章
|
2月前
|
安全 Java 数据库
一天十道Java面试题----第四天(线程池复用的原理------>spring事务的实现方式原理以及隔离级别)
这篇文章是关于Java面试题的笔记,涵盖了线程池复用原理、Spring框架基础、AOP和IOC概念、Bean生命周期和作用域、单例Bean的线程安全性、Spring中使用的设计模式、以及Spring事务的实现方式和隔离级别等知识点。
|
2月前
|
Java
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
这篇文章是Spring5框架的实战教程,深入讲解了AOP的基本概念、如何利用动态代理实现AOP,特别是通过JDK动态代理机制在不修改源代码的情况下为业务逻辑添加新功能,降低代码耦合度,并通过具体代码示例演示了JDK动态代理的实现过程。
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
|
2月前
|
XML Java 数据格式
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
这篇文章是Spring5框架的实战教程,主要介绍了如何在Spring的IOC容器中通过XML配置方式使用外部属性文件来管理Bean,特别是数据库连接池的配置。文章详细讲解了创建属性文件、引入属性文件到Spring配置、以及如何使用属性占位符来引用属性文件中的值。
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
|
21天前
|
XML Java 数据格式
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
Spring 第二节内容补充 关于Bean配置的更多内容和细节 万字详解!
119 18
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
|
8天前
|
XML Java 测试技术
spring复习01,IOC的思想和第一个spring程序helloWorld
Spring框架中IOC(控制反转)的思想和实现,通过一个简单的例子展示了如何通过IOC容器管理对象依赖,从而提高代码的灵活性和可维护性。
spring复习01,IOC的思想和第一个spring程序helloWorld
|
6天前
|
缓存 Java Spring
手写Spring Ioc 循环依赖底层源码剖析
在Spring框架中,IoC(控制反转)是一个核心特性,它通过依赖注入(DI)实现了对象间的解耦。然而,在实际开发中,循环依赖是一个常见的问题。
15 4
|
9天前
|
XML Java 开发者
经典面试---spring IOC容器的核心实现原理
作为一名拥有十年研发经验的工程师,对Spring框架尤其是其IOC(Inversion of Control,控制反转)容器的核心实现原理有着深入的理解。
31 3
|
22天前
|
Java 数据库连接 数据格式
【Java笔记+踩坑】Spring基础2——IOC,DI注解开发、整合Mybatis,Junit
IOC/DI配置管理DruidDataSource和properties、核心容器的创建、获取bean的方式、spring注解开发、注解开发管理第三方bean、Spring整合Mybatis和Junit
【Java笔记+踩坑】Spring基础2——IOC,DI注解开发、整合Mybatis,Junit
|
22天前
|
Java 数据库连接 Maven
Spring基础1——Spring(配置开发版),IOC和DI
spring介绍、入门案例、控制反转IOC、IOC容器、Bean、依赖注入DI
Spring基础1——Spring(配置开发版),IOC和DI
|
2月前
|
XML Java 数据格式
Spring5入门到实战------3、IOC容器-Bean管理XML方式(一)
这篇文章详细介绍了Spring框架中IOC容器的Bean管理,特别是基于XML配置方式的实现。文章涵盖了Bean的定义、属性注入、使用set方法和构造函数注入,以及如何注入不同类型的属性,包括null值、特殊字符和外部bean。此外,还探讨了内部bean的概念及其与外部bean的比较,并提供了相应的示例代码和测试结果。
Spring5入门到实战------3、IOC容器-Bean管理XML方式(一)
下一篇
无影云桌面