那什么才算 IoC?我们重申一次标准:
以下从应用对象是否自行查找依赖、以及谁负责组装对象来比较:
| 条件 | 是否满足 | 解释 |
|---|---|---|
| 你不创建依赖对象 | ✅ | Kitchen.createFood() or agent.getVehicle() 是“工厂”,你没直接 new |
| 业务对象是否被外部注入依赖 | 取决于调用位置 | 在组装代码中手动调用 setter 也可以实现 DI,不要求必须使用容器 |
| 容器是否负责自动组装 | ❌ | 这些调用本身不能证明使用了容器 |
所以更准确地说:
| 示例 | 是否 IoC? | 是否有 IoC 的“倾向/味道”? |
|---|---|---|
| Kitchen.createFood() + setFood() | 取决于组装位置 | 外部调用 setter 可构成 DI |
| agent.getVehicle() + setVehicle() | 取决于组装位置 | 业务内部查找属于 Service Locator |
| Spring.getBean(Food.class) 然后自动注入 | ✅ 是 | ✅ 容器管理依赖 |
一句话解释区别:
IoC 是思想(理念),DI 是具体实现方式之一。
来拆解下这两个词:
IoC(Inversion of Control)控制反转:
是一种 设计思想
目标是:把控制权从程序员手里“反转”给框架或容器
不再由你手动控制程序流程和对象组合,而是由框架来“自动调度”
比如:
依赖对象的创建与组合交给外部完成。
DI(Dependency Injection)依赖注入:
是一种 实现 IoC 的具体技术手段
它的核心是:将依赖通过某种方式“注入”给目标对象
有 3 种常见形式:
构造器注入
Setter 注入
接口注入
关系总结图:
IoC 是设计思想,DI 是实现依赖组合的一种方式。
| 对比项 | IoC | DI |
|---|---|---|
| 是什么 | 一种设计思想 | 一种实现方式 |
| 控制谁 | 控制“对象如何创建和依赖如何组合”的权力从你手中“反转”出去 | 指定“依赖应该怎么注入进来” |
| 关系 | 包含关系:DI 是 IoC 的一种实现手段 | 属于 IoC 的一种实践方式 |
| 举例 | Spring 框架控制 Bean 生命周期 | @Autowired 注入依赖 |
什么是 Service Locator?
Service Locator 是一种 设计模式,其核心目的是:
提供一个全局的服务查找器,通过它你可以在任何地方查找、获取到需要的服务或依赖对象,而不需要手动创建和管理。
换句话说,它是一个中介,负责管理对象的创建和查找。你只需要请求它来获取服务,而不用关心服务怎么创建或者存在哪儿。
核心思想:
从服务定位器(Service Locator)中获取服务,而不是自己直接管理和创建对象。
但是,这种方式的问题:
虽然 Service Locator 提供了“获取依赖”的能力,但它有一个隐含的缺点: 它破坏了“依赖显式化”的原则,也就是,你没有直接看出对象的依赖是什么,导致了代码的可维护性差,特别是当系统变得复杂时。
这和 DI 的区别:
DI 明确地告诉你:你需要哪些依赖,并且这些依赖会通过某种方式(构造器、setter 等)注入给你。
Service Locator 则是通过一个全局对象来管理和查找依赖,你在使用时不关心这些依赖怎么被创建的。
举个简单的例子:
没有 Service Locator(直接依赖注入):
public class Restaurant {
private final Food food;
public Restaurant(Food food) {
this.food = food;
}
public void order() {
food.eat();
}
}
通过构造器注入 Food,明确表达了 Restaurant 依赖于 Food。当你创建 Restaurant 时,需要显式地提供 Food。
使用 Service Locator:
public class Restaurant {
private Food food;
public void order() {
// 通过 Service Locator 获取 food
food = ServiceLocator.getService(Food.class);
food.eat();
}
}
在这个例子里,Restaurant 并不直接关心 Food 是怎么被创建的,它只是通过 ServiceLocator.getService(Food.class) 去查询获取 Food。
你不用显式地提供 Food,而是让 Service Locator 去处理。
Service Locator 类的简单实现:
import java.util.Map;
import java.util.HashMap;
public class ServiceLocator {
private static Map<Class<?>, Object> services = new HashMap<>();
// 注册服务
public static <T> void registerService(Class<T> serviceClass, T serviceInstance) {
services.put(serviceClass, serviceInstance);
}
// 获取服务
public static <T> T getService(Class<T> serviceClass) {
return serviceClass.cast(services.get(serviceClass));
}
}
在这段代码中,ServiceLocator 提供了一个静态方法来获取所有注册过的服务对象,而你不需要关心这些对象是怎么创建的。