什么是IoC?
控制反转是软件工程中的一项原则,它将对象或者程序的部分控制权转移到容器或框架上。我们最常在面向对象编程的上下文中使用它。
与我们自定义代码调用库的传统编程相比,IoC使框架能够控制程序流并调用我们的自定义代码。为了实现这一点,框架使用了带有附加行为的抽象。如果我们想添加我们自己的行为,我们需要扩展框架的类或插入我们自己的类。
IoC的优点是:
- 将任务的执行与其实现分离
- 更容易在不同的实现之间切换
- 程序的模块化程度更高
- 通过隔离组件或者模拟其依赖项,并允许组件通过协议进行通信,从而更轻松地测试程序
我们通过各种机制来实现控制反转,例如:策略设计模式、服务定位器模式、工厂模式和依赖注入(DI)。
什么是DI?
依赖注入是一种我们可以用来实现IOC的模式,其中被反转的控制是设置对象的依赖关系。将对象与其他对象联系,或将对象“注入”到其他对象中。
传统的编程中船舰对象依赖是这样的:
在上面的示例中,我们需要在Todo类本身中实例化Item接口的实现。
而通过使用DI,它是这样的:
通过使用DI,我们无需指定我们想要的Item的实现。
接下来我们将演示如何通过注解提供Item的实现。
Spring IoC容器
在Spring中,接口ApplicationContext表示IoC容器。Spring容器负责实例化、配置和组装成为bean的对象,以及管理他们的生命周期。
Spring提供了ApplicationContext接口的几种实现:
ClassPathXmlApplicationContext和FileSystemXmlApplicationContext用于独立的应用程序,以及WebApplicationContext用于Web应用程序。
为了组装bean,容器使用配置元数据,可以是XML配置或者注解的形式。
这是手动实例化容器的一种方式:
要在上面的示例中设置Item的属性,我们可以使用元数据。然后容器将读取此元数据并在运行时使用它来组装bean。
Spring的依赖注入可以通过构造函数、setter或属性来完成。
基于构造函数注入
基于Setter注入
基于对象属性注入
相对于其他两种方式,这种方式可能看起来更简单、更干净,但是不建议使用它,因为它有一些缺点,例如:
- 此方法使用反射来注入依赖项,这比基于构造函数或基于setter的注入成本高
如果我们想代码看起来简单干净可以是用Lombok的@RequiredArgsConstructor和@NonNull来实现构造函数注入:
可以在 Martin Fowler 的文章或Spring官网中阅读更多关于这些概念的信息:
- 控制容器反转和依赖注入模式 https://martinfowler.com/articles/injection.html
- 控制反转 https://martinfowler.com/bliki/InversionOfControl.html
- Spring 框架参考文档 https://docs.spring.io/spring-framework/docs/current/reference/html/#beans-dependencies