Spring 核心:IoC & DI 从原理到注解使用、注入方式全攻略(2026 最新版)
Spring 框架最核心、最闪耀的部分就是 IoC(Inversion of Control,控制反转) 和 DI(Dependency Injection,依赖注入)。它们是 Spring 实现“低耦合、高可维护、可测试”代码的基石。掌握 IoC & DI,你就真正掌握了 Spring 的灵魂。
1. IoC 与 DI 的核心概念与原理
IoC(控制反转)
传统方式:程序主动创建依赖对象(new)。
Spring 方式:控制权反转给容器,由 Spring IoC 容器负责对象的创建、装配和管理。
DI(依赖注入)
IoC 的具体实现方式:容器在创建对象时,自动将它所依赖的对象“注入”进来。
经典比喻:
- 传统:你饿了自己去厨房做饭(主动 new 依赖)。
- Spring:你坐在餐厅,服务员(IoC 容器)把菜(依赖对象)端给你(DI)。
IoC 容器做了什么?
- 创建对象(Bean)
- 管理对象生命周期(singleton/prototype 等)
- 装配对象之间的依赖关系
- 提供查找、AOP、事务等高级功能
2. Spring IoC 容器的两种主要实现
| 容器类型 | 接口/类 | 特点 | 使用场景 |
|---|---|---|---|
| BeanFactory | org.springframework.beans.factory.BeanFactory | 基础容器,提供最基本的 IoC 功能 | 资源极度受限的环境 |
| ApplicationContext | org.springframework.context.ApplicationContext | BeanFactory 的子接口,扩展了国际化、事件发布、AOP 等 | 几乎所有项目都用这个 |
常用实现类:
AnnotationConfigApplicationContext(注解配置,推荐)ClassPathXmlApplicationContext(XML 配置,已过时)
3. 依赖注入的三种方式(重点掌握)
Spring 支持三种注入方式,推荐优先级:构造器 > Setter > 字段。
| 注入方式 | 实现方式 | 推荐度 | 优点 | 缺点 | 示例代码 |
|---|---|---|---|---|---|
| 构造器注入 | 通过构造函数参数注入 | ★★★★★ | 依赖强制、不可变、便于测试、支持循环依赖解决 | 参数多时构造函数臃肿 | 最推荐 |
| Setter 注入 | 通过 setter 方法注入 | ★★★☆☆ | 支持可选依赖、灵活 | 依赖可变、运行时可能被修改 | 适合可选依赖 |
| 字段注入 | 直接 @Autowired 到字段 | ★☆☆☆☆ | 代码简洁 | 隐藏依赖、难以单元测试、违反封装原则 | 不推荐 |
构造器注入示例(推荐写法):
@Service
public class UserService {
private final UserRepository userRepository;
// Spring Boot 3 + 单构造器可省略 @Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public void save(User user) {
userRepository.save(user);
}
}
Setter 注入示例:
@Service
public class EmailService {
private MailSender mailSender;
@Autowired
public void setMailSender(MailSender mailSender) {
this.mailSender = mailSender;
}
}
字段注入示例(不推荐):
@Service
public class OrderService {
@Autowired
private PaymentService paymentService; // 隐藏依赖,测试麻烦
}
4. 注解驱动的 IoC & DI(现代 Spring 主流方式)
Spring 4+ 推荐完全基于注解配置,XML 已基本淘汰。
核心注解一览表
| 注解 | 作用位置 | 功能 | 示例 |
|---|---|---|---|
| @Component | 类 | 标记为 Spring 管理的 Bean(通用) | @Component public class MyService {} |
| @Service | 服务层类 | @Component 的语义化别名 | 业务逻辑层 |
| @Repository | 持久层类 | @Component + 异常翻译(持久层异常转 Spring 异常) | DAO/Repository |
| @Controller | Web 层类 | @Component + MVC 支持 | 传统 MVC |
| @RestController | REST API 类 | @Controller + @ResponseBody | 返回 JSON |
| @Configuration | 配置类 | 标记为配置类,通常配合 @Bean | 替代 XML 配置 |
| @Bean | 方法 | 方法返回值作为 Bean 交给容器管理 | 第三方类无法加 @Component 时使用 |
组件扫描:
@SpringBootApplication // 包含 @ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
默认扫描主类同包及其子包下的组件。
@Autowired 注入注解
| 注解 | 作用位置 | 功能 |
|---|---|---|
| @Autowired | 字段、构造器、Setter | 按类型自动注入(byType) |
| @Qualifier | 与 @Autowired 配合 | 指定 Bean 名称注入(解决同类型多个 Bean) |
| @Primary | 类上 | 同类型多个 Bean 时优先注入此 Bean |
| @Resource | 字段、Setter | JSR-250 注解,按名称注入(byName) |
| @Inject | 字段、构造器、Setter | JSR-330 标准注解,按类型注入 |
解决同类型多个 Bean 示例:
// 方案1:@Primary
@Primary
@Repository
public class MySqlUserDao implements UserDao {}
// 方案2:@Qualifier
@Autowired
@Qualifier("mySqlUserDao")
private UserDao userDao;
5. Bean 的作用域(Scope)
| 作用域 | 注解/配置 | 说明 |
|---|---|---|
| singleton | 默认 / @Scope(“singleton”) | 容器中只有一个实例(最常用) |
| prototype | @Scope(“prototype”) | 每次注入或获取都创建新实例 |
| request | @Scope(“request”) | Web 项目中,每个 HTTP 请求一个实例 |
| session | @Scope(“session”) | 每个 HTTP Session 一个实例 |
6. 生命周期回调
@Component
public class MyBean implements InitializingBean, DisposableBean {
@PostConstruct // 初始化后调用(推荐)
public void init() {
System.out.println("Bean 初始化完成");
}
@PreDestroy // 销毁前调用(推荐)
public void destroy() {
System.out.println("Bean 即将销毁");
}
@Override
public void afterPropertiesSet() throws Exception { /* InitializingBean */ }
@Override
public void destroy() throws Exception { /* DisposableBean */ }
}
7. 最佳实践总结
| 建议 | 原因 |
|---|---|
| 优先使用构造器注入 | 依赖明确、对象不可变、支持循环依赖 |
| 接口编程 + DI | 松耦合,便于测试和切换实现 |
| 避免字段注入 | 隐藏依赖、难以单元测试 |
| 使用 @Primary 或 @Qualifier | 优雅解决同类型 Bean 冲突 |
| 配置类用 @Configuration + @Bean | 管理第三方库 Bean |
| Lombok @RequiredArgsConstructor | 简化构造器注入代码 |
Lombok 优化示例:
@Service
@RequiredArgsConstructor // 自动生成含 final 字段的构造器
public class UserService {
private final UserRepository userRepository;
private final EmailService emailService;
}
8. 一句话总结
IoC 是设计思想:控制权从代码交给容器。
DI 是实现手段:容器把依赖“注入”给对象。
注解 + 构造器注入 是现代 Spring 的最佳实践。
掌握了 IoC & DI,你就拥有了编写优雅、可维护 Spring 应用的超级能力!
如果想深入探讨循环依赖原理、@Configuration 代理机制、手写简易 IoC 容器,或者结合 Spring Boot 的自动配置源码分析,随时告诉我,我继续带你飞!🚀