我们来一步步拆解这个问题。
到底是谁的“控制权”被“反转”了?
简单回答:是创建和管理对象的控制权被反转了。
再详细一点:是应用程序代码(我们自己写的业务代码)把对“依赖对象”的创建、查找和注入的控制权,“反转”或者说“交给了一个外部的容器(比如 Spring IoC 容器)。
从前是谁控制?(没有 IoC 的情况)
在没有 IoC 的世界里,我们自己的代码掌握着绝对的控制权。
让我们回到上一篇文章中那个 UserService
的例子:
public class UserService {
// 我(UserService)需要一个 UserRepository。
// 所以,我(UserService)自己来决定用哪个,并且自己来创建它!
// 这就是“正向控制”或者说“传统控制”。
private UserRepository userRepository = new MySqlUserRepository();
public void doSomething() {
// ...
}
}
在这个场景下,控制链条是这样的:
-
谁是主控方?
UserService
。 -
它控制了什么?
- 创建时机:当
new UserService()
被执行时,new MySqlUserRepository()
也立刻被执行。UserService
决定了MySqlUserRepository
的出生时间。 - 具体实现:
UserService
在代码里写死了MySqlUserRepository
,它直接控制了依赖的具体类型。如果想换,必须改UserService
的代码。 - 生命周期:
userRepository
实例的生命周期与UserService
实例紧密绑定。UserService
实例被销毁时,userRepository
实例也会被回收。
- 创建时机:当
总结一下:在传统模式下,一个对象如果需要依赖另一个对象,它必须亲自负责创建(或获取)这个依赖。这种主动、直接的控制方式,我们称之为“正向控制流”。
现在又是谁控制?(使用 IoC 的情况)
在使用了 IoC 之后,控制权从我们的业务代码,转移到了一个专门的“IoC 容器”手上。
我们再看 IoC 版本的代码:
@Service
public class UserService {
// 我(UserService)只是声明:我需要一个 UserRepository。
// 至于这个 UserRepository 是谁,从哪来,什么时候创建,我不管!
// 我等着别人(IoC容器)把它送过来。
private final UserRepository userRepository;
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public void doSomething() {
// ...
}
}
在这个场景下,控制链条发生了“反转”:
-
谁是主控方?
Spring IoC 容器。 -
它控制了什么?
- 创建时机:容器在启动时,会扫描并创建所有被管理的 Bean(比如
MySqlUserRepository
的实例)。它不再是由UserService
来决定。 - 具体实现:容器根据配置(比如哪个类上标了
@Repository
注解)来决定实例化哪一个UserRepository
的实现。UserService
完全不知道也不关心具体是MySqlUserRepository
还是MongoUserRepository
。 - 依赖注入:容器创建完
UserService
后,发现它需要一个UserRepository
,于是容器主动将自己管理的UserRepository
实例,“注入”(送)给UserService
。UserService
从“主动索取”变成了“被动接收”。
- 创建时机:容器在启动时,会扫描并创建所有被管理的 Bean(比如
总结:在 IoC 模式下,对象不再自己创建依赖,而是被动地等待容器将依赖注入进来。原来的主动方(UserService
)变成了被动方,而容器则成为了新的主动方。这个主客关系的颠倒,就是“控制反转”这个名字的精髓。
比喻:“好莱坞原则”
IoC 的思想有一个非常著名的别称,叫做**“好莱坞原则”(The Hollywood Principle)**。
这句话是:“Don’t call us, we’ll call you.”(别来找我们,我们会来找你。)
- 没有 IoC(你自己找工作):你(
UserService
)主动去给各个电影公司(new MySqlUserRepository()
,new OracleUserRepository()
)打电话,询问是否有工作机会。你控制着整个过程。 - 使用 IoC(你签约了经纪人):你(
UserService
)签约了一个顶级经纪人(Spring IoC 容器)。你只需要告诉经纪人:“我是一个演员,我需要角色(UserRepository
)”。然后你就回家等着。当有合适的角色时,经纪人会主动打电话给你,把剧本(依赖实例)给你。
在这个比喻里:
- 你(演员) 就是我们的业务组件,比如
UserService
。 - 经纪人 就是 IoC 容器。
- 打电话这个动作的“控制权”,从你手上,反转到了经纪人手上。
这就是“控制反转”的全部意义:将组件之间复杂的创建和依赖关系,从组件内部代码中剥离出来,交由一个中立的第三方容器去统一管理,从而实现解耦和更高的灵活性。