spring依赖注入通过容器管理对象创建实现解耦,推荐构造器注入(final字段+构造参数)保障不可变性与可测试性;多实现时用@qualifier或@primary精准定位;依赖抽象接口而非具体类,配合@profile实现环境配置驱动替换,避免修改业务逻辑。

Spring 的依赖注入(DI)实现对象解耦,核心在于把“谁来创建依赖”这件事从代码里抽出来,交给 Spring 容器统一管理。组件不再自己 new 对象、也不硬编码具体实现类,只声明“我需要什么”,至于“这个东西从哪来、怎么造”,全由容器负责——这样各层之间就不再绑死,改实现、换环境、写测试都变得轻量。
用构造器注入明确依赖边界
这是最推荐的方式,尤其适合必需且不可变的依赖。
- 在类中用 final 字段 + 构造函数参数 声明依赖,Spring 启动时自动按类型匹配并注入对应 Bean
- 没注入成功就直接启动失败,问题暴露在早期,避免运行时空指针
- 单元测试时可以直接 new 对象,传入 mock 实例,不依赖 Spring 上下文
- 配合 Lombok 的 @RequiredArgsConstructor,代码简洁又语义清晰
靠接口编程 + @Qualifier 精准定位多实现
当一个接口有多个实现(比如 PaymentService 有支付宝、微信两种),光靠类型无法唯一确定注入谁,就得加标识。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 在字段或构造参数上加 @Autowired @Qualifier("alipayService"),指定 Bean 名称
- 也可以在某个实现类上加 @Primary,标记为默认首选项,避免因扫描顺序导致意外注入
- 业务代码始终面向 PaymentService 接口 编程,完全不出现具体类名,新增支付方式只需加个新类 + 注册为 Bean
通过配置驱动替换行为,而非修改调用方
真正解耦的关键不是“怎么注入”,而是“依赖什么”——依赖抽象,而不是具体。
- Controller 层只依赖 UserService 接口,Service 层只依赖 UserDao 接口,每一层都只和上/下一层的契约打交道
- 不同环境(dev/test/prod)可通过 @Profile 激活不同配置类,比如开发用内存版 UserDao,生产用 MySQL 版
- 要切数据库、换缓存、加日志拦截器,都只需调整配置或新增实现,原有业务逻辑一行不用动
避开字段注入,守住可测试性底线
虽然 @Autowired 写在字段上最省事,但它会让对象状态失控、依赖关系隐形,给测试埋坑。
- 字段注入后,对象是否完整、哪些依赖必须存在,看代码根本看不出来
- 写单元测试时无法绕过容器,只能用 @MockBean 或加载整个上下文,又慢又重
- 构造器注入让依赖一目了然,也天然支持不可变设计,是更稳健的选择
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










