Java-022-控制反转和依赖注入

控制反转和依赖注入

控制反转

控制反转(Inversion of Control)是一种是面向对象编程中的一种设计原则,用来减低计算机代码之间的耦合度. 比如:

A依赖于B, 一种写法是在类A里面使用 new 创建一个类B的对象, 这就是一般所说的A控制B的创建和销毁

而控制反转, 则是让A移交出这个创建权给A的外部, 由外部(相对于A)控制B的创建和销毁. 这样就实现了B的创建和生命周期逻辑和A的解耦.

因为A类里的代码需要去new一个B的对象, 就需要调用B的构造方法: 更新了B的构造方法 –> A中调用的B的构造方法!
X –> A, B, C –> D

在X里创建D的对象, 然后再传给A, B, C

和封装实现细节的对比

依赖注入

通过控制反转, 我们把B的控制权转移到A的外部, 但是A仍然依赖于B, 需要使用B的对象去完成一些事情. 那问题来了:

我们如何把在外部创建的B的对象交给A呢?

  • 在A的构造方法里把B作为一个参数传给A
  • 使用setter方法把B传给A

这个其实就是所谓的依赖注入! 依赖注入其实就是控制反转的一个实现, 差不多也是同一回事.

组件和依赖注入

回忆之前讲Java程序的基本结构: 抽象出一些类和对象, 然后处理对象之间的交互.

然后在具体的场景中, 我们会有一些常用的对象来处理一些常见的逻辑结构, 比如说特定本地数据的访问, 数据库的访问, 配置文件访问, 认证, 这种我们会称之为组件或者模块, 在Spring里称之为Bean.

同一个组件通常可能会在程序中很多地方需要使用, 比如说 UserController 可能会使用到 UserDao 这个组件, ManageControler 也会使用到 UserDao 这个组件. 那最简单的方式是, 我们每次使用的时候都创建一个组件 UserDao 的实例, 即使这个组件是可以重用的! (这里违反了什么原则?)

但是有没有其他更好的方式呢? 就是统一管理组件的创建, 然后在需要使用的地方把这个组件的实例注入.

Spring的组件管理和依赖注入

常用的两种注入方式:

  • 组件直接标记注入
  • 工厂模式注入

区别

直接注入

如果需要被注入的组件, 是我们能够控制的, 那我们就可以使用直接标记注入, 简洁优雅.

工厂模式注入

如果需要注入的组件, 我们需要更复杂的控制创建过程, 比如说动态根据输入内容创建组件, 那就使用工厂模式注入.

或者需要注入的组件是一个外部库的类, 那我们没法给它加上@Component这样的标记, 那我们就必须使用工厂模式注入.

再或者, 我们希望控制组件的数量, 如果是只需要一个组件的实例, 则使用直接注入或者工厂模式都可以. 但是如果需要使用多个实例(比如每次使用都创建一个新的实例), 那就使用工厂模式!

代码链接