Spring框架中的IoC(控制反转)

什么是IoC

百度百科:

控制反转 (Inversion of Control,缩写为IoC ),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入 (Dependency Injection,简称DI),还有一种方式叫"依赖查找"(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。

简单来说,IoC是一种设计思想,它的目的是为了解耦。它的目的是为简化我们在开发过程中自我创建、管理对象的过程。

存在以下常见场景:

  • 存在一个模块需要被多个服务使用。

  • MVC架构中一个服务层可能依赖多个数据访问层。

  • 资源复用,例如:数据库连接池,线程池。

上述这些场景中本质上都是对于资源的重复创建使用,对于这种形式可能会出现下图中的情况:

对象间的依赖关系因系统复杂度提升变得越来越复杂,可能会出现多重依赖等问题。

为了解决解决该问题,我们引入IoC控制反转这种设计思想。在Spring框架中,IoC通过依赖注入(Depedency Injection,DI)的方式实现。

通过引入IoC我们的资源管理将变成下图所示的形式:

我们将对象的控制权交给IoC容器,通过容器控制对象的生命周期。


DI(依赖注入)

通过 DI(依赖注入) 实现 IoC 控制反转,通过将对象的依赖关系交由外部容器管理,解决代码耦合问题。核心思想是:对象不需要主动创建或者去查找依赖,而是直接接受容器注入的依赖即可。

依赖注入 的三种实现方式

  • Setter注入:通过Setter方法注入依赖(XML配置或@Autowired)注解。

  • 构造器注入:通过构造函数注入。

  • 字段注入:通过反射注入字段(@Autowird)。

DI 的实现原理

  1. 扫描 BeanDefinition:容器启动时扫描所有 Bean 的定义(XML、注解、Java 配置)。

  2. 创建 Bean 实例:通过反射或工厂方法实例化 Bean。

  3. 注入依赖:根据依赖类型或名称查找匹配的 Bean,递归完成所有依赖的注入。

  4. 初始化 Bean:调用 @PostConstruct 方法或实现 InitializingBean 接口。

三级缓存 机制

通过引入三级缓存机制解决循环依赖问题。

循环依赖指的是:A需要依赖B,B需要依赖A,出现这种互相依赖的情况。

缓存级别 存储内容 作用
一级缓存 完全初始化后的单例 Bean 直接提供可用 Bean
二级缓存 早期暴露的 Bean(未完成属性填充) 解决循环依赖
三级缓存 Bean 工厂(用于生成早期对象) 延迟创建代理对象(如 AOP 场景)

流程:

  1. 创建 A 实例(未填充属性)→ 放入三级缓存。

  2. 填充 A 的属性时发现依赖 B → 创建 B 实例。

  3. 填充 B 的属性时发现依赖 A → 从三级缓存获取 A 的工厂,生成早期对象并放入二级缓存。

  4. B 完成初始化 → 放入一级缓存。

  5. A 继续填充 B 的依赖 → 完成初始化并放入一级缓存。


Spring IoC 的工作流程

1、 容器初始化

  • 加载配置(XML/注解),生成 BeanDefinition。

  • 注册 BeanPostProcessor(扩展点,如 AOP 代理)。

  • 预实例化单例 Bean(非懒加载)。

2、Bean 生命周期

  • 实例化:反射或工厂方法创建对象。

  • 属性填充:注入依赖(DI)。

  • 初始化:执行 @PostConstruct、InitializingBean 等方法。

  • 销毁:调用 @PreDestroy 或 DisposableBean 方法。

0. BeanDefinition

通过BeanDefinition获取Bean的定义信息。

1. 构造函数

通过构造函数实例化Bean。

2. 依赖注入

进行Bean的依赖注入。

3. Aware接口

处理Aware接口:

  • BeanNameAware:获取Bean的名称。

  • BeanFactoryAware:获取Bean工厂。

  • ApplicationContextAware:获取容器上下文对象。

4. BeanPostProcessor#before

Bean前置处理器。

5. 初始化方法
6. BeanPostProcessor#after

Bean后置处理器,可以在内部通过AOP进行动态代理,增强Bean。

7. 销毁Bean

3、扩展机制

  • BeanPostProcessor:在 Bean 初始化前后插入逻辑(如 AOP)。

  • BeanFactoryPostProcessor:修改 BeanDefinition(如占位符替换)。

相关推荐
重庆小透明24 分钟前
力扣刷题记录【1】146.LRU缓存
java·后端·学习·算法·leetcode·缓存
lang2015092829 分钟前
Reactor操作符的共享与复用
java
TTc_40 分钟前
@Transactional事务注解的批量回滚机制
java·事务
wei_shuo1 小时前
飞算 JavaAI 开发助手:深度学习驱动下的 Java 全链路智能开发新范式
java·开发语言·飞算javaai
欧阳秦穆2 小时前
apoc-5.24.0-extended.jar 和 apoc-4.4.0.36-all.jar 啥区别
java·jar
岁忧2 小时前
(LeetCode 面试经典 150 题 ) 58. 最后一个单词的长度 (字符串)
java·c++·算法·leetcode·面试·go
Java初学者小白2 小时前
秋招Day14 - Redis - 应用
java·数据库·redis·缓存
代码老y2 小时前
Spring Boot + 本地部署大模型实现:优化与性能提升
java·spring boot·后端
GodKeyNet2 小时前
设计模式-桥接模式
java·设计模式·桥接模式
guojl3 小时前
Java多任务编排技术
java