IoC(Inversion of Control)和 DI(Dependency Injection)是面向对象编程中的两个相关概念,它们主要用于解决程序中的依赖管理和解耦问题。
1. IOC 控制反转
1.1. 概述
控制反转(英语:Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。
在传统的编程方式中,对象通常自行创建或查找它们依赖的对象。而在IoC模式下,这种创建和查找依赖对象的责任从应用程序代码中转移到了外部的第三方(通常是框架或容器),即所谓的“控制权反转”给了容器。
1.2. 核心思想
对象不再直接控制其依赖对象的创建和生命周期管理,而是由外部容器负责这些工作。容器知道哪些对象需要哪些依赖,并负责在适当的时候将依赖注入到需要它们的对象中。通过这种方式,对象之间的依赖关系变得更加透明,降低了耦合度,提高了代码的可重用性和可测试性。
1.3. 代码层面
Class A中用到了Class B的对象b,一般情况下,需要在A的代码中显式地用 new 创建 B 的对象。
使用 IoC 设计原则后,A 的代码只需要定义一个 private 的B对象,不需要直接 new 来获得这个对象,而是通过相关的容器控制程序来将B对象在外部new出来并注入到A类里的引用中。
IoC 将采用依赖注入或依赖查找两种方案去实现
2. DI 依赖注入
2.1. 概述
实现控制反转主要有两种方式:依赖注入和依赖查找。
依赖注入:被动的接收对象,在类A的实例创建过程中即创建了依赖的B对象,通过类型或名称来判断将不同的对象注入到不同的属性中。
依赖查找:主动索取相应类型的对象,获得依赖对象的时间也可以在代码中自由控制。
2.2. 核心思想
通过依赖注入,对象不再关心依赖对象的具体实现细节和生命周期管理,只需声明它需要哪些依赖(接口或抽象类型),由外部容器负责提供正确的依赖实例。这样,对象间的依赖关系变得松散,容易更改,有利于代码的解耦和测试。
3. 注册到IOC的方式
详细参考(【Spring系列笔记】定义Bean的方式)
在Spring Boot应用程序中,定义Bean是非常常见的操作,它是构建应用程序的基础。Spring Boot提供了多种方式来定义Bean,每种方式都有其适用的场景和优势。
3.1. @Bean
@Bean用于告诉Spring框架,被注解的方法将返回一个对象实例,该对象将被注册为Spring应用程序上下文中的bean。
@Bean注解通常用于配置类中的方法,用于创建和配置bean实例。通常第三方Bean需要在配置类中,使用该方式注册
3.2. @Component
@Component是Spring框架中用于标识类为Spring组件的注解。这意味着这些类可以被Spring容器管理,可以进行依赖注入,可以通过@Autowired或@Resources注解进行自动装配等。
被@Component标记的类要放在启动类的目录或者子目录下,不然需要在加上@ComponentScan来扫描。常用衍生的注解有
注解名 |
应用 |
@Controller @RestController |
控制器类注解 |
@Service |
业务逻辑类注解 |
@Repository |
实体类注解 |
@Configuration |
配置类 |
@ControllerAdvice @RestControllerAdvice |
全局异常处理类注解 |
3.3. @Import
@Import是Spring框架中的注解,用于在配置类中引入其他配置类或者普通的Java类。
当一个类被@Import注解标识时,它可以引入其他配置类,从而将其他配置类中定义的Bean引入到当前的配置类中。这样可以实现配置类的模块化管理,将不同功能的配置分开,提高配置类的可维护性和可读性。
3.4. BeanDefinition
在Spring框架中,BeanDefinition是一个接口,用于描述一个bean的配置元数据。BeanDefinition中包含了bean的类名、作用域、构造函数参数、属性值、初始化方法、销毁方法等配置信息。
BeanDefinition是Spring IoC容器中用于管理bean定义的核心接口,它是Spring框架中bean工厂的基础。在Spring容器启动时,会解析配置文件或注解,将bean的配置信息解析成BeanDefinition对象,并注册到容器中。
通过BeanDefinition,Spring容器可以了解每个bean的配置信息,从而实例化和管理bean。BeanDefinition中的配置信息包括了bean的各种属性和行为,通过这些信息,Spring容器可以实例化bean、进行依赖注入、初始化和销毁bean等操作。
4. DI注入方式
详细参考(【Spring系列笔记】DI注入方式)
4.1. 构造方法注入
构造器注入是指通过构造方法将依赖项注入到对象中。在构造方法中,将依赖项作为参数传入,然后在对象被创建时将其保存在成员变量中。
4.2. Setter方法注入
Setter方法注入是指通过setter方法将依赖项注入到对象中。在setter方法中,将依赖项作为参数传入,然后将其保存在成员变量中。
4.3. 注解注入
注解注入是指通过注解将依赖项注入到对象中。在依赖项上添加注解,然后在对象中使用@Autowired注解将依赖项注入到对象中。
4.4. 接口注入
接口注入是指通过实现接口将依赖项注入到对象中。在接口中定义依赖项的setter方法,然后在实现类中实现该方法,将依赖项注入到对象中。
优点 |
缺点 |
应用 |
|
构造方法注入 |
|
代码臃肿,可读性差 |
依赖项是必需的,且不需要在对象生命周期内发生变化(官方推荐) |
Setter 注入 |
|
无法注入不可变对象 |
依赖项可能发生变化,或者是可选的 |
接口注入 |
|
|
注入依赖项需要规范化或者实现快速切换时 |
注解注入 |
实现使用简单,方便维护 |
|
高频使用 |