首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >比 MQ 更轻的异步方案:Spring 内置的这个隐藏功能,很多人还不知道

比 MQ 更轻的异步方案:Spring 内置的这个隐藏功能,很多人还不知道

原创
作者头像
程序搭建开发i
发布2026-07-03 10:12:47
发布2026-07-03 10:12:47
110
举报

pring 本身就内置了一套事件驱动机制,轻量得很,专治同 JVM 内部的异步解耦场景

问题出在哪,先看看这段代码

你写过这种东西吗:

public void createOrder(OrderDTO dto) {

// 保存订单

orderService.save(dto);

// 发短信

smsService.sendOrderSuccessSms(dto.getPhone());

// 加积分

pointsService.addPoints(dto.getUserId(), 100);

// 推送站内信

notificationService.push(dto.getUserId(), "订单创建成功");

// 记操作日志

logService.record("下单成功", dto.getOrderId());

}

作者见过不少人写,自己也写过,一个"创建订单"的方法,里头塞了短信、积分、通知、日志,五件事挤一块儿

核心问题是,短信发没发、积分加没加,跟订单创建成不成功其实没啥关系,你把这些非核心逻辑全硬编码进来,它们就和主流程死死绑在一块了

哪天产品说再加个功能,比如下单后更新用户等级,你就得打开这个方法,再加一行,方法越来越长,越来越臃肿,谁维护谁头疼

Spring 事件机制是咋回事

Spring 从很早就有 ApplicationEvent 这套东西,原理是观察者模式(Observer Pattern),说白了就是发布订阅

发布方扔一个事件出去,不管谁在监听、有几个人在监听,它发完就走,不等,不管

监听方自己注册感兴趣的事件,事件来了自己处理,和发布方互不认识,互不干扰

整套机制跑在 JVM 内部,没有网络开销,没有消息队列中间件,比 MQ 省资源,延迟更低,部署也没额外的组件依赖,适合同服务内部的异步解耦这种场景

三步搞定,核心就这些

先定义事件

// 继承 ApplicationEvent,把要传递的业务数据带上

public class OrderCreatedEvent extends ApplicationEvent {

private final String orderId;

private final String phone;

private final Long userId;

public OrderCreatedEvent(Object source, String orderId, String phone, Long userId) {

super(source);

this.orderId = orderId;

this.phone = phone;

this.userId = userId;

}

// getter 略

}

就是个普通 Java 类,继承ApplicationEvent,把业务数据搁里头,没什么复杂的

主流程发布事件

@Service

@RequiredArgsConstructor

public class OrderService {

private final ApplicationEventPublisher eventPublisher;

public void createOrder(OrderDTO dto) {

// 只干核心事:保存订单

orderRepository.save(buildOrder(dto));

// 发完就走,后续谁处理不管

eventPublisher.publishEvent(

new OrderCreatedEvent(this, dto.getOrderId(), dto.getPhone(), dto.getUserId())

);

}

}

注入ApplicationEventPublisher,一句publishEvent了事,主流程干净利落,没有任何短信积分的影子

监听器各干各的

@Component

public class OrderEventListener {

// @Async 让监听器异步执行,不加默认同步

@EventListener

@Async

public void sendSms(OrderCreatedEvent event) {

smsService.sendOrderSuccessSms(event.getPhone());

}

@EventListener

@Async

public void addPoints(OrderCreatedEvent event) {

pointsService.addPoints(event.getUserId(), 100);

}

@EventListener

@Async

public void recordLog(OrderCreatedEvent event) {

logService.record("下单成功", event.getOrderId());

}

}

每个监听方法管一件事,互不干扰,Spring 自动根据事件类型路由过来

@Async 这个注解注意下,不加的话监听是同步执行的,发布方会等监听方跑完才往下走,这就跟没异步一样了,想真正解耦得加上,同时启动类加个 @EnableAsync 开关:

@SpringBootApplication

@EnableAsync

public class Application {

public static void main(String[] args) {

SpringApplication.run(Application.class, args);

}

}

新增功能,核心代码一行不用动

如果客户说下单后还要给用户推一条站内信,直接在监听器里加个方法:

@EventListener

@Async

public void sendNotification(OrderCreatedEvent event) {

notificationService.push(event.getUserId(), "您的订单已提交成功");

}

OrderService 里的 createOrder 方法,一个字都不用动

以前那种写法,你得打开核心方法,加一行,提交,走 code review,万一改出问题还得背锅,现在你根本不需要碰那块代码,稳得很

什么时候用 Spring 事件,什么时候上 MQ

这俩不是替代关系,别搞混了

判断是这样的:

用 Spring 事件:同一个服务内部的异步解耦,不需要跨服务通信,不需要消息持久化,不需要断了还能重投,对消息丢失不敏感的场景

发个短信失败了大不了记个日志,用 Spring 事件够了,零中间件,零配置,上手五分钟

上 MQ:需要跨服务消费,需要消息不能丢,需要消费方单独扩容,需要延时消息或者死信队列这些高级功能,那就老老实实引 MQ,别省这点事

两个工具用途不一样,别因为 MQ 听起来高端就什么都加,也别因为 Spring 事件轻量就觉得它能全部替代 MQ,各有各的地盘,用对了才省心

总结一下这套东西的核心价值:主流程只干主流程的事,旁路逻辑全交给监听器,新增功能加监听器,删功能删监听器,核心代码很稳。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 问题出在哪,先看看这段代码
  • Spring 事件机制是咋回事
  • 三步搞定,核心就这些
  • 新增功能,核心代码一行不用动
  • 什么时候用 Spring 事件,什么时候上 MQ
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档