当前位置: 首页 > news >正文

手把手教会你什么是 Spring 事件监听 —— 解耦神器,告别“面条代码”!(Spring Boot 实战)

视频看了几百小时还迷糊?关注我,几分钟让你秒懂!(发点评论可以给博主加热度哦)


一、真实业务痛点:为什么你需要事件监听?

想象你在开发一个用户注册系统,注册成功后要:

  1. 发送欢迎邮件;
  2. 发送短信验证码;
  3. 记录操作日志;
  4. 初始化用户积分;
  5. 推送消息到企业微信……

❌ 反例:全部写在注册方法里

@Service public class UserService { public void register(User user) { // 1. 保存用户 userRepository.save(user); // 2. 发邮件 emailService.sendWelcomeEmail(user.getEmail()); // 3. 发短信 smsService.sendVerificationCode(user.getPhone()); // 4. 记日志 logService.log("用户注册", user.getId()); // 5. 初始化积分 pointService.initPoints(user.getId()); // 6. 推送企业微信 wechatService.pushRegisterMessage(user.getName()); } }

🚨问题爆炸

  • 方法又长又臭,像“意大利面条”;
  • 每新增一个功能(比如加“发优惠券”),就要改核心注册逻辑;
  • 如果发邮件失败,整个注册就失败?不合理!
  • 单元测试困难,要 mock 所有依赖。

这就是典型的“高耦合”代码!


二、什么是 Spring 事件监听?一句话讲透

Spring 事件监听 = 观察者模式 + Spring 容器管理
它允许你:发布一个事件,所有关心这个事件的组件自动响应,彼此完全解耦!

就像你发朋友圈:

  • 你只管“发布”动态(事件);
  • 好友 A 点赞,好友 B 评论,好友 C 转发(监听器);
  • 你不需要知道谁会响应,他们也不需要知道你是谁!

三、手把手实战:用事件监听重构用户注册

第一步:定义自定义事件

// 继承 ApplicationEvent(Spring 4.2+ 后可省略,但建议保留) public class UserRegisteredEvent extends ApplicationEvent { private final User user; public UserRegisteredEvent(Object source, User user) { super(source); this.user = user; } public User getUser() { return user; } }

💡source通常是发布事件的对象(如当前 Service),可用于追踪来源。


第二步:在注册成功时发布事件

@Service public class UserService { // 注入 Spring 的事件发布器 @Autowired private ApplicationEventPublisher eventPublisher; public void register(User user) { // 1. 保存用户(核心逻辑) userRepository.save(user); // 2. 发布事件!后续操作全部解耦 eventPublisher.publishEvent(new UserRegisteredEvent(this, user)); } }

关键:注册方法现在只做“注册”,其他事交给监听器!


第三步:编写多个监听器(每个只做一件事)

📧 邮件监听器
@Component public class EmailListener { @EventListener // ←←← 核心注解! public void handleUserRegistered(UserRegisteredEvent event) { User user = event.getUser(); System.out.println("【邮件服务】发送欢迎邮件给: " + user.getEmail()); // emailService.send(...); } }
📱 短信监听器
@Component public class SmsListener { @EventListener public void handleUserRegistered(UserRegisteredEvent event) { User user = event.getUser(); System.out.println("【短信服务】发送验证码到: " + user.getPhone()); // smsService.send(...); } }
📝 日志监听器
@Component public class LogListener { @EventListener public void handleUserRegistered(UserRegisteredEvent event) { User user = event.getUser(); System.out.println("【日志服务】记录用户注册: " + user.getId()); // logService.log(...); } }

优势

  • 每个监听器职责单一;
  • 新增“发优惠券”?只需写一个新监听器,注册逻辑一行都不用改

四、高级用法:让事件更强大

1️⃣ 异步监听(避免阻塞主流程)

默认事件是同步的(监听器执行完才返回)。如果发邮件很慢,用户要等很久!

✅ 解决方案:加@Async

@Component public class AsyncEmailListener { @EventListener @Async // ←←← 开启异步(需在启动类加 @EnableAsync) public void handleUserRegistered(UserRegisteredEvent event) { // 模拟耗时操作 try { Thread.sleep(3000); } catch (Exception e) {} System.out.println("【异步邮件】发送完成!"); } }

⚠️ 注意:在Application.java上加@EnableAsync


2️⃣ 条件监听(只处理特定事件)

@EventListener(condition = "#event.user.vip == true") public void handleVipUserRegistered(UserRegisteredEvent event) { System.out.println("【VIP 专属】发送豪华礼包!"); }

使用 SpEL 表达式,灵活过滤。


3️⃣ 监听 Spring 内置事件

Spring 自己也会发布事件,比如容器启动完成:

@Component public class StartupListener { @EventListener public void onContextRefreshed(ContextRefreshedEvent event) { System.out.println("【系统启动】应用已初始化完毕!"); // 可用于加载缓存、预热数据等 } }

常用内置事件:

事件触发时机
ContextRefreshedEventApplicationContext 初始化或刷新完成
ContextClosedEventApplicationContext 关闭
RequestHandledEventWeb 请求处理完成

五、反例对比:为什么不用 if-else 或直接调用?

方案耦合度扩展性异常处理可测试性
直接调用(反例)高(UserService 依赖所有服务)差(改核心代码)全局回滚难(要 mock 所有)
事件监听(正例)零耦合极好(加监听器即可)独立失败不影响主流程每个监听器单独测

💡特别提醒
如果某个监听器失败(比如邮件服务挂了),不会影响其他监听器和主流程
(除非你手动抛异常并配置了事务回滚)


六、完整 Spring Boot 示例

1. 项目结构

src/main/java ├── event/ │ └── UserRegisteredEvent.java ├── listener/ │ ├── EmailListener.java │ ├── SmsListener.java │ └── LogListener.java ├── service/ │ └── UserService.java └── Application.java // 加 @EnableAsync

2. 启动类

@SpringBootApplication @EnableAsync // 开启异步支持 public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }

3. 测试 Controller

@RestController public class TestController { @Autowired private UserService userService; @PostMapping("/register") public String register(@RequestBody User user) { userService.register(user); return "注册成功!后续操作已异步执行。"; } }

调用:

POST /register { "name": "张三", "email": "zhangsan@example.com", "phone": "13800138000" }

控制台输出:

注册成功!后续操作已异步执行。 【日志服务】记录用户注册: 1 【短信服务】发送验证码到: 13800138000 【异步邮件】发送完成!

七、注意事项 & 最佳实践

⚠️ 1. 事件对象应该是不可变的(Immutable)

  • 避免监听器修改事件数据,导致其他监听器拿到脏数据;
  • 建议用final字段 + 构造函数初始化。

⚠️ 2. 不要在监听器中写核心业务逻辑

  • 事件监听适合非核心、可降级的操作(通知、日志、统计等);
  • 核心逻辑(如扣款、库存)仍应在主流程中处理。

⚠️ 3. 异步监听的异常处理

  • 默认异步异常会被吞掉!建议加全局异常处理器:
@Component public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler { @Override public void handleUncaughtException(Throwable ex, Method method, Object... params) { System.err.println("异步监听器异常: " + ex.getMessage()); } }

⚠️ 4. 事务边界问题

  • 如果发布事件的方法有@Transactional,监听器默认在同一事务中;
  • 若需监听器在事务提交后执行,用@TransactionalEventListener

八、总结:事件监听的核心价值

场景传统写法事件监听
用户注册后发邮件UserService 直接调 EmailServiceUserService 发事件,EmailListener 监听
订单支付后更新库存OrderService 调 InventoryServiceOrderService 发事件,InventoryListener 监听
系统启动加载缓存在 main 方法里写监听 ContextRefreshedEvent

记住
“我不关心谁来处理,我只负责通知” —— 这就是事件驱动的魅力!


视频看了几百小时还迷糊?关注我,几分钟让你秒懂!(发点评论可以给博主加热度哦)

http://www.jsqmd.com/news/322043/

相关文章:

  • 用户个人资料编辑功能:测试要点、陷阱与最佳实践
  • 机床排屑机厂家报价口碑推荐,选购、运维与售后关键要点分析
  • 2026年1月云真机、云手机、安卓云手机、苹果云手机、ios云手机厂家实力综合分析:天勤网络登顶
  • 订单提交手动测试流程指南
  • Claude Code提示词案例(开发联系我们页面,表单使用Element Plus的el-form组件实现)
  • 2026年 展位设计公司推荐排行榜:主题展位/品牌展位/特装展位/大小面积展位设计搭建,创意视觉与高效落地的专业服务商精选
  • 国内四大AI编程IDE对比(二):从零构建桌面应用实测(补上Trae,幸亏补上了)
  • ACPI!ACPIBuildProcessDeviceGenericEvalStrict函数和BuildRequest->CurrentObject的由来
  • 一个杀手级 prompt
  • Google Genie 3 技术架构拆解:世界模型如何为 Agent 训练提供无限环境
  • threoninamide;DFCYDWOTPTH-NH₂
  • 雨生红球藻主流品牌全景解析(2026年最新版)
  • 基于springboot的电影评价管理系统设计实现
  • 2026年 实验室气路系统厂家推荐排行榜:气体管路、集中供气、汇流排专业解决方案,安全高效精准供气
  • python的crypto模块no model解决方法
  • HTTP 请求方法选择与 RESTful 实践(对比 GraphQL、RPC)
  • mhpkg 文件使用方法
  • 微商企业未来迭代的核心方向与多元探索——以链动2+1模式AI智能名片商城小程序为核心支撑
  • 胡杨映碧水,金沙绕蓝湾,这是罗布湖独有的沙漠浪漫
  • 文件与文件夹批量更名工具FileReNameTool V2.1.1支持撤销改名
  • 2026室内门十大品牌推荐:品质家居的安心之选
  • 写论文软件哪个好?实测5款后,虎贲等考AI凭3大硬核优势封神
  • 期刊论文投稿屡被拒?虎贲等考 AI:从选题到录用的学术发表加速器
  • Java毕设项目推荐-基于Java的饮品店销售管理系统的设计与实现基于SpringBoot的奶茶店线上点单与库存管理系统设计与实现【附源码+文档,调试定制服务】
  • 2026年 展台设计搭建厂家推荐排行榜:全球创意展台、科技感展台、吸睛展台设计公司实力解析与优选指南
  • Java毕设项目推荐-基于SpringBoot的船舶动态跟踪海洋航运管理系统的设计与实现船舶管理、货物运输、人员调度【附源码+文档,调试定制服务】
  • 许昌家庭装修机构性价比高的是哪家
  • 5 款 AI 写论文哪个好?实测后发现:虎贲等考 AI 才是毕业论文 “合规高效双在线” 的真黑马
  • 大屏自适应方案进阶:从基础缩放到多维度适配的完整实践
  • 虎贲等考 AI 智能写作:重新定义学术创作,全流程 AI 赋能让论文写作更高效