IOC控制反转深度解析

个人总结就是,原本我们的对象需要自己new,现在不需要,但与之替代的是写配置,告诉IOC哪些对象不用new,你给我搞了,我朝你要,朝你要的过程就是创建IOC容器,并调用getBean()方法。

至于DI,个人理解是我造汽车前要轮子,IOC去给我把轮子准备好,这就是IOC创建,然后把轮子放我这来,这就是DI(总不能造好了我自己取吧),和原本相比就是,service里面需要dao,之前dao我们是自己new的,现在不需要,现在我们用构造器,或者setter,又或者是@Autowire (自动注入)

一、什么是控制反转(Inversion of Control)?

控制反转是一种设计思想 ,核心是将对象的创建、管理和依赖关系的控制权从应用程序代码本身转移到外部容器(IOC 容器),实现 "反转" 对象的控制权。

1.1 传统方式 vs IOC 方式:理解 "反转" 的本质

维度 传统方式(主动控制) IOC 方式(被动接收)
对象创建 开发者在代码中主动通过new关键字创建对象(如UserService service = new UserService(); 对象由 IOC 容器创建,开发者通过容器 "获取" 对象(如UserService service = container.getBean("userService");
控制权归属 应用程序代码(开发者手动控制对象的生命周期) 外部 IOC 容器(容器统一控制对象的创建、初始化、销毁)
依赖管理 对象自己负责创建依赖(如UserServicenew UserDao() 依赖由容器自动 "注入" 到对象中,对象无需关心依赖的创建

举例说明

  • 传统方式:你(开发者)需要喝奶茶时,亲自去买(new 奶茶()),全程自己控制。
  • IOC 方式:你告诉奶茶店(IOC 容器)你要喝奶茶,奶茶店做好后直接递给你(容器提供对象),你无需关心制作过程,控制权在奶茶店。

二、IOC 容器:对象的 "管家"

IOC 容器是实现控制反转思想的具体载体,它负责管理应用中所有被纳入管理的对象(称为 "Bean"),并协调对象之间的依赖关系。

2.1 Bean:IOC 容器管理的对象

"Bean" 是 IOC 容器中管理的对象(可以是 Service、Dao、工具类等)。容器对 Bean 的管理包括:

  • 创建:根据配置(如 XML、注解)实例化 Bean;
  • 初始化 :调用初始化方法(如init-method);
  • 依赖注入:将关联的 Bean 注入到当前 Bean 中;
  • 销毁 :容器关闭时调用销毁方法(如destroy-method)。

2.2 IOC 容器的核心功能

  1. Bean 的生命周期管理

    容器从 Bean 的创建到销毁全程托管,开发者无需手动处理对象的创建和销毁,减少资源泄露风险。

  2. 依赖关系绑定(依赖注入 DI)

    当 Bean 之间存在依赖(如UserService依赖UserDao),容器会自动将依赖的 Bean "注入" 到目标 Bean 中,无需开发者在代码中手动创建依赖。

  3. 配置灵活性

    通过配置(注解、XML、配置类)定义 Bean 的创建规则和依赖关系,无需修改代码即可调整对象的创建逻辑。

三、依赖注入(DI):IOC 的实现手段

依赖注入(Dependency Injection)是实现控制反转的具体方式:当一个对象(A)依赖另一个对象(B)时,IOC 容器会主动将 B 实例注入到 A 中,而不是由 A 自己创建 B。

3.1 DI 的核心思想

"谁依赖谁,依赖什么,谁注入谁,注入什么"

  • 谁依赖谁:应用程序中的 Bean(如UserService)依赖 IOC 容器;
  • 依赖什么:Bean 依赖容器提供的其他 Bean(如UserService依赖UserDao);
  • 谁注入谁:IOC 容器向 Bean 注入依赖;
  • 注入什么:容器将依赖的 Bean 实例注入到目标 Bean 中。

3.2 依赖注入的常见方式

  1. 构造器注入

    通过 Bean 的构造方法传递依赖,容器在创建 Bean 时调用构造器并传入依赖的实例。

    java

    运行

    java 复制代码
    public class UserService {
        private UserDao userDao;
        
        // 构造器注入:容器通过此构造器传入UserDao实例
        public UserService(UserDao userDao) {
            this.userDao = userDao;
        }
    }
  2. setter 方法注入

    通过 Bean 的 setter 方法设置依赖,容器在创建 Bean 后调用 setter 传入依赖的实例。

    java

    运行

    java 复制代码
    public class UserService {
        private UserDao userDao;
        
        // setter注入:容器调用此方法传入UserDao实例
        public void setUserDao(UserDao userDao) {
            this.userDao = userDao;
        }
    }
  3. 字段注入(注解方式)

    通过注解(如 Spring 的@Autowired)直接在字段上标记依赖,容器自动将依赖注入到字段中。

    java

    运行

    java 复制代码
    public class UserService {
        // 字段注入:容器自动将UserDao实例注入到该字段
        @Autowired
        private UserDao userDao;
    }

四、IOC 的优势

  1. 降低耦合度

    对象之间的依赖关系由容器管理,而非硬编码在代码中,减少了对象之间的直接关联(如new操作)。

  2. 提高代码复用性

    容器管理的 Bean 可被多个对象共享,无需重复创建。

  3. 便于测试

    依赖由容器注入,测试时可轻松替换依赖为模拟对象(如 Mock),无需修改原代码。

  4. 简化开发

    开发者无需关注对象的创建和依赖管理,专注于业务逻辑实现。

  5. 增强扩展性

    通过修改配置即可替换 Bean 的实现(如将MySQLDao替换为OracleDao),无需修改依赖它的代码。

五、常见的 IOC 容器

  • Spring 容器:Java 生态中最流行的 IOC 容器,支持 XML、注解、Java 配置类等多种方式定义 Bean 和依赖。
  • Google Guice:轻量级 IOC 容器,基于注解实现依赖注入。
  • PicoContainer:轻量级容器,专注于最小化和高性能。

六、总结

  • IOC(控制反转) 是一种思想:将对象的控制权从应用程序转移到外部容器。

  • IOC 容器是实现这一思想的工具:负责 Bean 的创建、生命周期管理和依赖绑定。

  • DI(依赖注入) 是 IOC 的具体实现:容器将依赖的 Bean 注入到目标 Bean 中,解决对象之间的依赖关系。

通过 IOC,应用程序的代码结构更清晰、耦合度更低、可维护性和扩展性更强,是现代框架(如 Spring)的核心思想之一。

相关推荐
dylan_QAQ7 分钟前
【附录】Spring AOP 基础知识及应用
后端·spring
dylan_QAQ31 分钟前
【附录】Spring 配置属性绑定 基础及应用
后端·spring
dylan_QAQ36 分钟前
【附录】Spring 缓存支持 基础及应用
后端·spring
笑衬人心。1 小时前
缓存的三大问题分析与解决
java·spring·缓存
duration~2 小时前
SpringAI实现Reread(Advisor)
java·人工智能·spring boot·spring
YuforiaCode2 小时前
24SpringCloud黑马商城微服务整合Seata重启服务报错的解决办法
java·spring·微服务
蓝眸少年CY3 小时前
(第三篇)spring cloud之Zookeeper注册中心
spring·spring cloud·zookeeper
dylan_QAQ4 小时前
【附录】Spring 环境配置 基础及应用
后端·spring
dylan_QAQ5 小时前
【附录】Spring 资源访问 基础及应用
后端·spring