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(如占位符替换)。

相关推荐
bingbingyihao10 分钟前
多数据源 Demo
java·springboot
在努力的前端小白5 小时前
Spring Boot 敏感词过滤组件实现:基于DFA算法的高效敏感词检测与替换
java·数据库·spring boot·文本处理·敏感词过滤·dfa算法·组件开发
一叶飘零_sweeeet7 小时前
从繁琐到优雅:Java Lambda 表达式全解析与实战指南
java·lambda·java8
艾伦~耶格尔8 小时前
【集合框架LinkedList底层添加元素机制】
java·开发语言·学习·面试
一只叫煤球的猫8 小时前
🕰 一个案例带你彻底搞懂延迟双删
java·后端·面试
最初的↘那颗心8 小时前
Flink Stream API 源码走读 - print()
java·大数据·hadoop·flink·实时计算
JH30739 小时前
Maven的三种项目打包方式——pom,jar,war的区别
java·maven·jar
带刺的坐椅10 小时前
轻量级流程编排框架,Solon Flow v3.5.0 发布
java·solon·workflow·flow·solon-flow
David爱编程10 小时前
线程调度策略详解:时间片轮转 vs 优先级机制,面试常考!
java·后端
阿冲Runner11 小时前
创建一个生产可用的线程池
java·后端