什么是依赖注入(Dependency Injection,DI)
依赖注入是一种实现 控制反转(IoC, Inversion of Control) 的设计模式,它的核心思想是将对象的依赖(如其他类或服务)通过外部容器进行注入,而不是由对象自身去创建或管理依赖。
核心概念
- 依赖:一个对象需要另一个对象来完成某些任务。例如,A 类依赖于 B 类。
- 注入:由外部容器(如 Spring 容器)负责将 B 类的实例传递给 A 类,而不是由 A 类直接创建 B 类的实例。
依赖注入的好处
解耦合:
- 对象之间通过接口或约定进行交互,而不是直接创建依赖。
- 提升了代码的灵活性和可测试性。
更好的测试支持:通过注入模拟(Mock)依赖,可以轻松编写单元测试。
易于扩展:新的实现可以替换已有实现,而无需修改依赖的代码。
配置集中化:依赖关系由容器管理,配置可以通过外部文件或注解完成。
Spring 中依赖注入的发展历程
Spring 框架在 IoC 和依赖注入领域起到了开创性作用。以下是 Spring 中依赖注入的发展历程及不同阶段的实现方式:
1. XML 配置方式(Spring 1.x 和 2.x 阶段)
在早期的 Spring 版本中,依赖注入主要通过 XML 文件配置。
示例:
- 特点:
- 配置清晰,所有依赖关系集中在 XML 文件中。
- 灵活,但 XML 配置可能会过于冗长。
2. 注解方式(Spring 引入)
为了简化 XML 配置,Spring 引入了基于注解的依赖注入方式。
示例:
@Component
public class MyService {
// 服务逻辑
}
@Component
public class MyController {
@Autowired
private MyService myService; // 自动注入
}
- 核心注解:
- @Component:将类声明为 Spring 管理的 Bean。
- @Autowired:自动注入依赖(按类型注入)。
- 特点:
- 减少了 XML 配置,代码更加简洁。
- 注解方式更贴近开发人员的编码习惯。
3. Java Config 配置方式(Spring 3.x 引入)
Spring 3.x 引入了基于 Java 类的配置方式,完全用 Java 代码替代 XML。
示例:
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyService();
}
@Bean
public MyController myController(MyService myService) {
return new MyController(myService);
}
}
- 特点:
- 配置文件是 Java 代码,具备类型检查和 IDE 支持。
- 更加直观和灵活,适合复杂的配置场景。
4. 基于 Spring Boot 的自动配置(Spring 4.x 和 5.x)
Spring Boot 推出了自动配置机制,大幅简化了依赖注入和 Bean 配置。
示例:
@Service
public class MyService {
// 业务逻辑
}
@RestController
public class MyController {
private final MyService myService;
@Autowired
public MyController(MyService myService) {
this.myService = myService; // 构造器注入
}
@GetMapping("/hello")
public String sayHello() {
return "Hello, World!";
}
}
- 特点:
- 使用默认配置,减少了开发者手动配置的工作量。
- Spring Boot 自动扫描 @Component 和子类注解(如 @Service、@Repository 等)来注册 Bean。
- 构造器注入成为推荐的方式,避免了字段注入的隐式依赖。
总结
阶段 | 方式 | 优点 | 缺点 |
XML 配置 | 配置文件注入 | 配置清晰、集中化 | 配置冗长,开发效率较低 |
注解方式 | @Autowired 等 | 简化配置,贴近编码习惯 | 配置分散,不易于管理 |
Java Config | Java 配置类注入 | 类型安全、直观,配置灵活 | 对于简单场景可能显得复杂 |
Spring Boot | 自动配置 | 最少配置,快速开发微服务和现代应用 | 可能过度依赖自动配置 |