控制
要阐明控制反转的概念,先要明白什么是控制。举例有两个对象,如电池Battery和它的规格参数Parameter,他们可以有如下关系:1
2
3
4
5class Battery {
Parameter parameter = new Parameter();
Battery() {}
...
}
从代码中这样的关系可以看出:
- Battery类对象的构成是依赖于Parameter类对象的
- 在创建一个Battery类对象时,会随之创建一个Parameter类对象
- 在删除Battery类对象时,其Parameter成员对象也会随之删除
- 从前两点可以看出,Battery对象的生命周期决定了Parameter成员对象的生命周期,即控制
控制反转
控制反转是一种面向对象编程中的一种设计原则,用来降低计算机代码之间的耦合度,即解开对象与对象之间的控制关系,可以让Battery交出Parameter的创建权给外部,将上面的代码改成:
1 | class Battery{ |
这样写可以在外部创建Parameter对象,再传入Battery对象,当Battery对象生命周期结束时,Parameter对象可以继续存在,即实现了控制反转,控制反转可以实现对象之间的解耦,减少代码的重复
依赖注入
将所依赖的对象,传递给将使用的从属对象,就是依赖注入,而依赖注入是控制反转的具体实现方法
在前面的代码中,虽然已经成功实现了Battery对象与Parameter对象的解耦,将Parameter对象的控制权转移到了外部,但是Battery对象对Parameter对象的依赖依然存在,需要Parameter对象的传递才能完成构造,因此依赖注入是控制反转的具体实现方法
通过控制反转,把B的控制权转移到A的外部,但是A仍然依赖于B,需要使用B的对象去完成一些事情,那问题来了:我们如何把在外部创建的B的对象交给A呢?
- 在A的构造方法里吧B作为一个参数传给A——更加清晰
- 使用Setter方法把B传给A的成员变量——更加灵活
这就是依赖注入,依赖注入实际上是控制反转的一个实现
Spring组件和依赖注入
依赖注入逻辑:抽象出一些类和对象,然后处理对象之间的交互
在具体的场景中,我们会有一些常用的对象来处理一些常见的逻辑结构,比如说特定本地数据的访问,数据库的访问、认证,这种我们会称之为组件或者模块,在Spring里称之为Bean,同一个组件通常可能会在程序中很多地方需要使用,比如说UerController可能会使用到UserDao这个组件,ManageController也会用到UserDao这个组件
为避免代码重复,统一管理组件的创建, 然后在需要使用的地方把这个组件的实例注入
Spring里的一些逻辑
1 | @Component //告诉Spring,这是一个组件,可以用来注入到其他的对象里 |
运行顺序:
1.创建UserController –> new UserController(UserMockDao);–>需要另外一对象(组件)UserMockDao
2.先创建UserMockDao –> 创建UserController
问题
怎么告诉Spring选择性地选择哪个Component?
常用的两种注入方式
- 组件直接标记注入:如果需要被注入的组件,是我们能够控制的,那用直接标记注入简洁优雅
- 工厂模式注入
工厂模式
工厂模式是一种常用的创建型设计模式,提供了一种创建对象的最佳模式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
使用场景
1.需要注入的组件, 我们需要更复杂的控制创建过程, 比如说动态根据输入内容创建组件
2.需要注入的组件是一个外部库的类, 我们没法给它加上@Component这样的标记
3.控制组件的数量, 如果是只需要一个组件的实例, 则使用直接注入或者工厂模式都可以. 需要使用多个实例时(每次使用都创建一个新的实例),选择工厂模式,同一套代码可以创建多个对象
通用工厂类代码
1 | import org.springframework.beans.factory.FactoryBean; |