尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

Java-Spring 依赖注入详解 - 从零开始理解 - 若

Java-Spring 依赖注入详解 - 从零开始理解 - 若
📅 发布时间:2026/6/20 6:02:13

Spring 依赖注入详解 - 从零开始理解

📚 什么是依赖注入?

生活中的例子

想象一下,你是一个餐厅老板,你需要一个厨师来做饭。

传统方式(不用依赖注入):

// 你需要自己去找厨师,自己雇用一个
public class Restaurant {private Chef chef = new Chef(); // 自己创建厨师对象public void makeFood() {chef.cook();}
}

依赖注入方式:

// 你只需要说"我需要一个厨师",系统会自动给你分配一个
public class Restaurant {@Autowiredprivate Chef chef; // 系统自动给你一个厨师对象public void makeFood() {chef.cook();}
}

依赖注入(Dependency Injection,简称 DI)就是:你不需要自己去创建对象,系统会自动给你提供需要的对象。


🎯 为什么需要依赖注入?

传统方式的缺点

// 方式1:硬编码,不灵活
public class OrderService {private EmailService emailService = new EmailService(); // 写死了,只能发邮件
}// 方式2:如果换一种通知方式(比如发短信),需要修改代码
public class OrderService {private SmsService smsService = new SmsService(); // 改成发短信,代码要改
}

依赖注入的优势

// 使用接口,可以随时切换实现
public class OrderService {@Autowiredprivate NotificationService notificationService; // 可以是邮件,也可以是短信// 如果需要换实现,只需要换一个实现类,这里的代码不需要改
}

好处:

  1. ✅ 解耦合:代码更灵活,容易维护
  2. ✅ 易测试:可以轻松替换成测试用的假对象
  3. ✅ 代码简洁:不需要自己 new 对象

🔍 Spring 依赖注入的核心概念

1. 什么是 Bean?

Bean 就是被 Spring 管理的对象。

@Component  // 这个注解告诉 Spring:这个类需要你管理
public class Chef {public void cook() {System.out.println("厨师在做饭");}
}

有了 @Component,Spring 就会:

  • 创建 Chef 对象
  • 把这个对象放到一个"对象仓库"里
  • 当你需要的时候,自动给你提供

2. 如何告诉 Spring 你需要什么?

使用 @Autowired 注解:

public class Restaurant {@Autowired  // 告诉 Spring:我需要一个 Chef 对象,请自动给我private Chef chef;
}

📖 实战案例:FastBee 项目中的依赖注入

让我们通过 FastBee 项目中 GB/T28181 SIP 服务器的代码,来看看依赖注入是如何工作的。

案例背景

在 SIP 服务器中:

  • SipLayer 类需要启动 SIP 服务器
  • 启动服务器需要用到 IGBListener(监听器)来处理收到的消息

代码实现

第一步:创建需要被注入的类(Bean)

// GBListenerImpl.java
@Component  // 👈 关键:告诉 Spring,这个类需要被管理
public class GBListenerImpl implements IGBListener {@Override@Async("taskExecutor")public void processRequest(RequestEvent evt) {// 处理收到的 SIP 请求String method = evt.getRequest().getMethod();// ... 处理逻辑}// 其他方法...
}

解释:

  • @Component 让 Spring 知道这个类需要管理
  • Spring 会自动创建 GBListenerImpl 的对象
  • 这个对象会被放到 Spring 的"对象仓库"中

第二步:在需要的地方声明依赖

// SipLayer.java
@Configuration
public class SipLayer {@Autowired  // 👈 关键:告诉 Spring,我需要一个 IGBListener 对象private IGBListener gbSIPListener;  // 注意:这里用的是接口类型@Bean("udpSipServer")public SipProvider startUdpListener() throws Exception {// 使用 gbSIPListenerudpSipProvider.addSipListener(gbSIPListener);return udpSipProvider;}
}

解释:

  • @Autowired 告诉 Spring:我需要一个 IGBListener 类型的对象
  • Spring 会在"对象仓库"中查找
  • 找到了 GBListenerImpl(它实现了 IGBListener)
  • Spring 自动把 GBListenerImpl 的对象赋值给 gbSIPListener

完整流程图示

┌─────────────────────────────────────────┐
│  Spring 容器启动                         │
└─────────────────────────────────────────┘↓
┌─────────────────────────────────────────┐
│  1. 扫描 @Component 注解                 │
│     发现 GBListenerImpl                  │
└─────────────────────────────────────────┘↓
┌─────────────────────────────────────────┐
│  2. 创建 GBListenerImpl 对象             │
│     GBListenerImpl listener = new       │
│         GBListenerImpl();               │
└─────────────────────────────────────────┘↓
┌─────────────────────────────────────────┐
│  3. 把对象存到"仓库"中                   │
│     类型:IGBListener                    │
│     实例:listener                       │
└─────────────────────────────────────────┘↓
┌─────────────────────────────────────────┐
│  4. 扫描 @Autowired 注解                 │
│     发现 SipLayer.gbSIPListener         │
└─────────────────────────────────────────┘↓
┌─────────────────────────────────────────┐
│  5. 从仓库中找到 IGBListener 类型        │
│     找到了 GBListenerImpl 实例           │
└─────────────────────────────────────────┘↓
┌─────────────────────────────────────────┐
│  6. 自动赋值                             │
│     sipLayer.gbSIPListener = listener;  │
└─────────────────────────────────────────┘↓
┌─────────────────────────────────────────┐
│  完成!现在可以使用 gbSIPListener 了      │
└─────────────────────────────────────────┘

🛠️ 依赖注入的三种方式

方式1:字段注入(最简单,最常用)

public class Restaurant {@Autowiredprivate Chef chef;  // 直接在字段上注解
}

优点: 代码简洁
缺点: 不利于测试(不能轻易替换)

方式2:构造函数注入(推荐)

public class Restaurant {private Chef chef;// 通过构造函数注入@Autowiredpublic Restaurant(Chef chef) {this.chef = chef;}
}

优点: 更容易测试,依赖关系更明确
缺点: 代码稍微多一点

方式3:Setter 方法注入

public class Restaurant {private Chef chef;// 通过 setter 方法注入@Autowiredpublic void setChef(Chef chef) {this.chef = chef;}
}

优点: 可以在创建对象后再注入
缺点: 使用较少


💡 常见问题解答

Q1: 为什么用接口类型,不用具体类?

// ✅ 好的做法:使用接口
@Autowired
private IGBListener gbSIPListener;  // 接口类型// ❌ 不好的做法:使用具体类
@Autowired
private GBListenerImpl gbSIPListener;  // 具体类

原因:

  • 更灵活:如果以后换一个实现类,代码不需要改
  • 符合面向接口编程的原则

Q2: 如果有多个实现类怎么办?

// 假设有两个实现类
@Component
public class GBListenerImpl implements IGBListener { }@Component
public class TestListenerImpl implements IGBListener { }// 这时需要指定用哪个
@Autowired
@Qualifier("gbListenerImpl")  // 指定 Bean 的名称
private IGBListener listener;

Q3: 如果没有实现类会怎样?

@Autowired
private IGBListener listener;  // 如果找不到实现类// Spring 启动时会报错:
// No qualifying bean of type 'IGBListener' available

解决方法:

  • 创建一个实现类并加上 @Component
  • 或者使用 @Autowired(required = false) 让依赖变为可选

📝 总结

依赖注入的核心步骤

  1. 定义 Bean:在类上加上 @Component(或 @Service、@Repository 等)
  2. 声明依赖:在需要的地方加上 @Autowired
  3. Spring 自动完成:Spring 会自动创建对象并注入

记忆口诀

你定义,我注入,Spring 帮你来管理

类比记忆

传统方式 依赖注入
自己买食材做菜 点外卖(告诉系统你要什么,系统给你送)
自己找员工 HR 帮你招人
自己管理库存 仓库管理员帮你管理

🎓 下一步学习

理解了依赖注入后,你可以继续学习:

  1. Spring Bean 的作用域(单例、原型等)
  2. @Qualifier 和 @Primary(多个实现时如何选择)
  3. 循环依赖问题(A 依赖 B,B 依赖 A 怎么办)
  4. 生命周期回调(@PostConstruct、@PreDestroy)

📚 参考代码

本文示例代码来自 FastBee 开源项目:

  • GBListenerImpl: springboot/fastbee-server/sip-server/src/main/java/com/fastbee/sip/server/impl/GBListenerImpl.java
  • SipLayer: springboot/fastbee-server/sip-server/src/main/java/com/fastbee/sip/server/SipLayer.java

项目地址:https://github.com/Kerwin1202/fastbee


希望这篇文章能帮你理解 Spring 依赖注入!如果有问题,欢迎讨论。 🚀

相关新闻

  • 《创业之路》-754-《架构思维:从程序员到CTO》第二部分:架构师的六大生存法则与启发
  • Doris为2.1版本,但json_each不可以用解决方法
  • 微信小程序uniapp-vue校园租房指南房屋租赁

最新新闻

  • MC9S08SH32硬件断点与调试系统深度解析
  • Java CompletableFuture 异步编排实战
  • DeepTutor:你的智能学习伙伴,让AI辅导无处不在
  • 鸿蒙 Next 相亲防骗雷达 App 开发实战:防骗教育 + 交互式自测 + 内容驱动设计
  • 免熏蒸木箱个性化方案哪家好? - 工业品牌热点
  • 嵌入式音频设计:I2S/SAI时序解析与低功耗模式实战

日新闻

  • 信任的进化:技术实现详解——如何用JavaScript构建博弈论模拟器
  • Terrakube自定义工作流:如何集成OPA、Infracost等工具扩展IaC能力
  • grunt-concurrent快速入门:5分钟学会并行运行Grunt任务

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号