Redis-rb订阅发布模式实战:实现实时消息系统的完整指南
2026/4/21 4:03:36
依赖注入是 Spring 框架的核心机制,也是控制反转(Inversion of Control,IoC)的具体实现方式。它彻底改变了传统 Java 开发中“对象自己创建依赖对象”的方式,转而由 Spring IoC 容器负责创建、管理和注入对象之间的依赖关系,从而实现低耦合、高可维护性、可测试性。
传统方式(紧耦合):
publicclassUserService{privateUserDaouserDao=newUserDaoImpl();// 自己new依赖对象publicvoidsave(){userDao.save();}}依赖注入方式(松耦合):
publicclassUserService{privateUserDaouserDao;// 只声明依赖,不负责创建// 通过构造器、Setter 或字段注入publicvoidsetUserDao(UserDaouserDao){this.userDao=userDao;}publicvoidsave(){userDao.save();}}Spring 容器会在运行时把UserDao的实现对象自动“注入”到UserService中。
核心好处:
| 注入方式 | 说明 | 推荐程度 | 示例代码 |
|---|---|---|---|
| 构造器注入 | 通过构造函数参数注入依赖 | ★★★★★ | 最推荐(强制依赖、不可变、易测试) |
| Setter 注入 | 通过 setter 方法注入 | ★★★☆☆ | 适合可选依赖 |
| 字段注入 | 直接在字段上使用 @Autowired | ★☆☆☆☆ | 不推荐(难以测试、隐藏依赖、违反封装原则) |
构造器注入示例(推荐):
@ServicepublicclassUserService{privatefinalUserDaouserDao;// 构造器注入(Spring 4.3+ 单构造器可省略 @Autowired)publicUserService(UserDaouserDao){this.userDao=userDao;}publicvoidsave(){userDao.save();}}Setter 注入示例:
@ServicepublicclassUserService{privateUserDaouserDao;@AutowiredpublicvoidsetUserDao(UserDaouserDao){this.userDao=userDao;}}字段注入示例(不推荐):
@ServicepublicclassUserService{@AutowiredprivateUserDaouserDao;// 隐藏依赖,单元测试麻烦}@Autowired是 Spring 提供的最常用注解,可作用在:
按类型自动注入(byType):
Spring 默认按照类型匹配 Bean。如果同类型有多个 Bean,会报错(NoUniqueBeanDefinitionException)。
解决多个同类型 Bean 的方案:
@Primary@ComponentpublicclassMySqlUserDaoimplementsUserDao{}@Autowired@Qualifier("mySqlUserDao")privateUserDaouserDao;Spring Boot 进一步简化了 DI 配置:
// 接口publicinterfaceUserRepositoryextendsJpaRepository<User,Long>{}// 实现(Spring Data JPA 自动提供)@Repository// 可省略,Spring Boot 自动识别publicinterfaceUserRepository{...}// 服务层@ServicepublicclassUserService{privatefinalUserRepositoryuserRepository;publicUserService(UserRepositoryuserRepository){this.userRepository=userRepository;}publicUserfindById(Longid){returnuserRepository.findById(id).orElse(null);}}Spring 的 IoC 容器主要有两种:
常用实现:
| 作用域 | 说明 | 默认 |
|---|---|---|
| singleton | 单例(容器中只有一个实例) | 是 |
| prototype | 每次注入或获取都创建新实例 | 否 |
| request | Web 项目中,每个 HTTP 请求一个实例 | 否 |
| session | 每个 HTTP Session 一个实例 | 否 |
| application | 整个 ServletContext 一个实例 | 否 |
使用方式:
@Component@Scope("prototype")publicclassPrototypeBean{}| 建议 | 原因 |
|---|---|
| 优先使用构造器注入 | 依赖明确、对象不可变、便于测试 |
| 接口编程 + DI | 松耦合,便于切换实现 |
| 避免字段注入 | 隐藏依赖、难以单元测试 |
| 使用 @Primary 或 @Qualifier | 解决同类型多个 Bean 的冲突 |
| 结合 Lombok 的 @RequiredArgsConstructor | 简化构造器注入代码 |
Lombok 优化示例:
@Service@RequiredArgsConstructor// 自动生成含 final 字段的构造器publicclassUserService{privatefinalUserRepositoryuserRepository;}依赖注入是 Spring 的灵魂:它把“谁依赖谁、谁创建谁”的控制权从代码中剥离,交给容器管理,让你的代码更干净、更灵活、更易维护。
掌握了 DI,你就真正掌握了 Spring 的精髓!如果想深入探讨循环依赖如何解决、@Configuration 的代理机制、或者手写一个简易 IoC 容器,欢迎继续问我!🚀