Spring IOC详解
Spring IOC详解
一、什么是 IoC(控制反转)
一句话理解
对象的创建和依赖关系的管理,不再由程序员控制,而是交给 Spring 容器管理。
二、先看“没有 IoC”的写法
1 | class UserService { |
问题:
- 强耦合(UserService 依赖具体实现)
- 不利于扩展(换实现类要改代码)
- 不方便测试(无法 mock)
三、有 IoC 后的写法
1 | class UserService { |
现在:
UserDao不是自己 new 的- 而是由外部(Spring)传进来
四、什么是“控制反转”
传统方式:
1 | 程序员 → 控制对象创建 |
IoC:
1 | Spring容器 → 控制对象创建 |
控制权“反转”了!
五、Spring IoC 解决了什么问题?
Spring 本质就是一个对象工厂:
它负责:
- 创建对象(Bean)
- 管理对象生命周期
- 维护依赖关系
- 自动注入依赖
IoC的思想就是两方之间不互相依赖,由第三方来管理相关资源,这样做可以:
- 对象之间的耦合度或者说是依赖程度降低;
- 资源变得容易管理。
六、核心概念:Bean
Bean = 被 Spring 管理的对象
1 |
|
这个类就会被 Spring 扫描并创建成 Bean
七、依赖注入(DI)
IoC 的实现方式就是 DI(Dependency Injection)
常见三种方式:
7.1 构造器注入(推荐⭐)
1 |
|
7.2 属性注入(不推荐)
1 |
|
7.3 setter 注入
1 |
|
八、IoC 的底层原理(面试重点🔥)
8.1 读取配置
- XML / 注解 / Java Config
8.2 BeanDefinition
- 把类的信息解析成 Bean 定义
8.3 反射创建对象
1 | Class.forName().newInstance() |
8.4 依赖注入
- 通过构造器 / setter / 字段赋值
8.5 放入容器(Map)
1 | Map<String, Object> singletonObjects |
九、IoC 带来的好处
| 优点 | 说明 |
|---|---|
| 解耦 | 不依赖具体实现 |
| 可扩展 | 易替换实现 |
| 易测试 | 支持 mock |
| 生命周期管理 | Spring 统一管理 |
| 提高开发效率 | 少写重复代码 |
十、一个形象比喻
传统开发
你自己做饭:
- 买菜
- 做饭
- 洗碗
IoC
你点外卖:
- 你只负责吃
- 厨房(Spring)帮你做好一切
十一、总结(面试速答模板)
IoC(控制反转)是指将对象的创建和依赖关系的管理交给 Spring 容器来完成,而不是由程序员手动 new 对象。
传统的开发方式往往是在类A中手动new一个B对象,使用IoC思想的开发方式是:不使用new关键字来创建对象,而是通过IoC容器来帮助我们实例化对象,需要那个对象直接去IoC容器中取即可。
Spring 通过依赖注入(DI)实现 IoC,常见方式包括构造器注入、setter 注入和字段注入。
IoC 的本质是降低耦合,提高代码的可维护性和可扩展性。
可以。直接用一个真实开发中非常常见的场景来说明:👉「用户下单 + 支付方式切换」。
十二、场景说明使用IoC的好处
12.1 场景:电商系统支付模块
你要写一个 OrderService,负责下单并调用支付。
系统支持:
- 支付宝
- 微信支付
- 以后可能还要加:银行卡、Apple Pay…
12.2 不使用 IoC 的写法(问题很典型)
1 | class OrderService { |
🚨 问题分析
- 强耦合
1 | OrderService → 绑定 AlipayService |
如果改成微信支付:
1 | WeChatPayService weChatPayService = new WeChatPayService(); |
必须修改源码
- 扩展性差
如果要支持多种支付:
1 | if (type.equals("alipay")) { |
违反 开闭原则(OCP)
- 测试困难
你想测试:
- 成功支付
- 支付失败
但你没法替换 AlipayService(不能 mock)
12.3 使用 IoC + DI 的写法
- 第一步:定义接口(解耦核心)
1 | interface PayService { |
- 第二步:不同实现
1 |
|
- 第三步:OrderService 不再自己创建对象
1 |
|
12.4 IoC 带来的实际好处
- 解耦(最核心)
1 | OrderService → 依赖接口 PayService |
不关心具体实现是谁
- 扩展性极强
新增一个支付方式:
1 |
|
不需要修改 OrderService 一行代码
- 支持动态切换(配置驱动)
比如:
1 |
直接切换实现
甚至可以:
- 根据配置文件
- 根据环境(dev/test/prod)
- 更容易测试
1 | class MockPayService implements PayService { |
测试时直接注入 mock:
1 | new OrderService(new MockPayService()); |
- 生命周期统一管理
Spring 可以控制:
- 单例 / 多例
- 初始化
- 销毁
你不用手动管理对象
12.5 核心变化总结
| 维度 | 不用 IoC | 使用 IoC |
|---|---|---|
| 对象创建 | 自己 new | Spring 管 |
| 依赖关系 | 写死 | 自动注入 |
| 扩展性 | 差 | 强 |
| 测试 | 困难 | 简单 |
| 耦合度 | 高 | 低 |
12.6 一句话总结(面试用)
在实际开发中,比如支付模块,如果不使用 IoC,业务类会直接依赖具体实现,导致强耦合、难扩展。而使用 IoC 后,通过依赖注入依赖接口,Spring 负责实例创建和注入,使系统具备良好的解耦性、扩展性和可测试性。