在Spring框架中,IOC(控制反转,Inversion of Control)和DI(依赖注入,Dependency Injection)是核心概念。它们帮助开发者构建松耦合、可测试且易于维护的应用程序。
一、什么是Spring“控制反转”
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来降低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
在软件工程中,控制反转(IoC)是一种编程原则。与传统控制流程相比,IoC反转了控制流程。在IoC中,计算机程序的自定义编写部分接收来自通用框架的控制流程。与传统程序编程相比,具有这种设计的软件架构反转了控制:在传统编程中,表示程序目的的自定义代码调用可重用库来处理一般任务,但在控制反转中,框架调用自定义或特定于任务的代码。
简单描述就是,对象a中用到了对象b,一般情况下,需要在a的代码中显示的new一个b的对象。使用控制反转设计原则后,a中只需要定义一个对象b,不需要实例化new,而是通过相关的容器控制程序来将b对象在外部new出来并赋值给a中的b。控制反转有时被戏称为“好莱坞原则:不要打电话给我们,我们会打电话给你”。
二、什么是Spring“依赖注入”
依赖注入(Dependency Injection)是Spring框架的核心之一。
在软件工程中,依赖注入是一种设计模式,其中一个对象或函数接收它所依赖的其他对象或函数。依赖注入是控制反转的一种形式,旨在分离构造对象和使用对象的关注点,从而生成松散耦合的程序。该模式确保希望使用给定服务的对象或函数不必知道如何构造这些服务具体实现。相反,接收“客户机”(对象或函数)由外部代码(“注入器”)提供其依赖关系,而它无需感知实现细节。
简单描述就是,在控制反转中提到相关的容器控制程序来将b对象在外部new出来并赋值给a中的b,这个就是依赖注入的过程。
三、IoC和DI的关系
IoC(控制反转)主要指将对象的创建权交给外界(例如Spring容器),这里的交给外界就是控制反转的过程,在对象创建过程中普遍会依赖其他的对象资源,所以需要外界对原始对象进行属性依赖的赋值操作,这个过程就是DI(依赖注入)。在这里我们要清楚是将手动创建对象的权利反转给Spring容器,Spring容器对创建的对象进行依赖注入。所以IoC和DI是相辅相成的搭档,IoC需要DI进行依赖的赋值,他们都是为实现解耦而服务的。
四、IoC的主要优点
- 降低耦合度:对象不再直接依赖于其他对象的实现,而是依赖于接口或抽象类。
- 提高可测试性:由于对象之间的依赖关系可以轻松替换,单元测试变得更加简单。
- 模块化开发:各个组件可以独立开发和维护,提高了代码的复用性和灵活性。
五、IoC容器的作用
- 实例化对象:根据配置文件或注解,创建和管理Bean实例。
- 管理依赖关系:自动解析并注入对象所需的依赖。
- 生命周期管理:管理Bean的生命周期,包括初始化、销毁等操作。
六、DI的三种主要方式
1. 构造器注入(Constructor Injection)
通过构造函数传递依赖项。这种方式适用于必须提供的依赖项,确保对象在创建时就已经具备所有必要的依赖。
public class MyService {
private final MyRepository repository;
@Autowired
public MyService(MyRepository repository) {
this.repository = repository;
}
}
2、Setter注入(Setter Injection)
通过setter方法设置依赖项。这种方式适用于可选的依赖项,允许在对象创建后再进行配置。
public class MyService {
private MyRepository repository;
@Autowired
public void setRepository(MyRepository repository) {
this.repository = repository;
}
}
3、字段注入(Field Injection)
直接在字段上标注@Autowired注解,由Spring自动注入依赖项。这种方式虽然简洁,但不如构造器注入和Setter注入灵活,也不利于单元测试。
public class MyService {
@Autowired
private MyRepository repository;
}
七、DI的主要优点
- 解耦合:对象不需要知道如何创建它的依赖项,只需要声明它需要什么依赖项。
- 易于配置:依赖关系可以通过XML配置文件、注解或Java配置类进行管理,方便修改和扩展。
- 支持AOP:依赖注入与面向切面编程(AOP)结合,可以更方便地实现横切关注点(如日志记录、事务管理等)。
八、总结
Spring的IoC和DI使得应用程序更加模块化、松耦合,并且易于测试和维护。通过将对象的创建和依赖管理交给Spring容器,开发者可以专注于业务逻辑的实现,而不必担心复杂的依赖关系管理和生命周期管理。
在实际开发中,合理使用IoC和DI可以帮助我们构建更加健壮、灵活且易于扩展的应用程序。