Spring Event详解 加技术架构图 代码实现

-------------------------------------------------------------------------------------------------------------------

Spring Event 事件驱动机制 超详细完整版

 

一、什么是 Spring Event

 
Spring 内置轻量级事件监听模型,基于观察者模式
 
  • 作用:同一个微服务内业务解耦
  • 特点:内存级、非持久化、同步 / 异步均可
  • 局限:仅限本 JVM、服务重启事件丢失、不跨微服务
  • 用途:提醒通知、日志记录、状态变更、后置处理
 

 

二、核心三大角色

 
  1. 事件(Event):自定义业务事件,继承 ApplicationEvent
  2. 发布者(Publisher):ApplicationEventPublisher 发送事件
  3. 监听者(Listener):@EventListener 监听并处理业务
 

 

三、架构原理图(文字可视化架构图)

 
plaintext
 
 
┌────────────────────────────────── 【单个微服务 JVM内存】──────────────────────────────────┐
│                                                                                         │
│  业务Service 【事件发布方】                                                             │
│     publishEvent(自定义事件)                                                             │
│           ↓                                                                             │
│  Spring 事件中心(内存队列)                                                            │
│           ↓↓↓ 多路分发                                                                 │
│  ┌─────────────┐   ┌─────────────┐   ┌─────────────┐   ┌─────────────┐                │
│  │ 站内信监听  │   │ APP推送监听│   │ 短信通知监听│   │ 日志记录监听│                │
│  └─────────────┘   └─────────────┘   └─────────────┘   └─────────────┘                │
└─────────────────────────────────────────────────────────────────────────────────────────┘

❌ 无法跨其他微服务
❌ 服务重启、宕机 → 未消费事件全部丢失
❌ 无持久化、无重试机制
 
 

架构特点

 
  1. 发布方与监听方完全解耦,互不依赖
  2. 一个事件 → 多个监听器同时执行
  3. 默认同步执行,加 @Async 变为异步
  4. 无磁盘存储,纯内存运行
 

 

四、完整可直接复制代码(案件提醒场景)

 

1、自定义业务事件(RemindCreatedAfterEvent)

 
java
 
运行
 
 
 
import org.springframework.context.ApplicationEvent;

/**
 * 案件提醒创建完成事件
 */
public class RemindCreatedAfterEvent extends ApplicationEvent {

    private final LasReminderRecord lasReminderRecord;

    public RemindCreatedAfterEvent(LasReminderRecord lasReminderRecord) {
        super(lasReminderRecord);
        this.lasReminderRecord = lasReminderRecord;
    }

    public LasReminderRecord getLasReminderRecord() {
        return lasReminderRecord;
    }
}
 
 

2、事件发布(你原有业务代码)

 
java
 
运行
 
 
 
import org.springframework.context.ApplicationEventPublisher;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;

@Service
public class CaseRemindService {

    @Resource
    private ApplicationEventPublisher publishEvent;

    public void sendCaseRemind() {
        // 1. 保存提醒入库
        LasReminderRecord record = saveRemindToDb();

        // 2. 发布Spring事件
        publishEvent.publishEvent(new RemindCreatedAfterEvent(record));
    }
}
 
 

3、事件监听(异步处理通知)

 
java
 
运行
 
 
 
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Component
public class RemindEventListener {

    /**
     * 监听提醒创建事件 - 异步处理站内信
     */
    @Async
    @EventListener
    public void handleRemindMsg(RemindCreatedAfterEvent event) {
        LasReminderRecord record = event.getLasReminderRecord();
        // 业务:发送站内消息
        sendInnerMsg(record);
    }

    /**
     * 第二个监听器:APP推送
     */
    @Async
    @EventListener
    public void handleRemindPush(RemindCreatedAfterEvent event) {
        // 业务:APP推送通知
    }

    /**
     * 第三个监听器:短信通知
     */
    @Async
    @EventListener
    public void handleRemindSms(RemindCreatedAfterEvent event) {
        // 业务:发短信
    }
}
 
 

4、开启异步配置(启动类加注解)

 
java
 
运行
 
 
 
@SpringBootApplication
@EnableAsync // 开启Spring异步事件
public class CaseApplication {
}
 
 

 

五、同步 VS 异步区别

 
  1. 默认同步
 
  • 发布事件 → 等待所有监听器执行完毕才继续
  • 事务一致,重启依然会丢
  • 监听器报错,会回滚主业务
 
  1. @Async 异步
 
  • 主线程立刻结束,后台线程处理
  • 性能高
  • 服务重启必丢事件,无法回溯
 

 

六、核心优缺点总结

 

优点

 
  1. 代码解耦,新增通知不用改原有业务
  2. 使用简单,Spring 原生,无需中间件
  3. 一个事件多监听,扩展方便
  4. 支持事务绑定、有序执行
 

缺点

 
  1. 纯内存,服务重启事件丢失
  2. 仅限单个微服务,不能跨服务
  3. 无消息堆积、无重试、无死信
  4. 大量事件会耗尽 JVM 内存
 

 

七、业务选型建议(你的案件提醒)

 
  • 内部流程、日志、状态变更 → 用 Spring Event
  • 短信、APP 推送、重要待办提醒 → 必须用 RocketMQ/Kafka(不丢消息、跨服务)

-------------------------------------------------------------------------------------------------------------------

Spring 事件发布监听机制(Spring Event) 微服务重启后会丢失么

直白结论(一秒看懂)

Spring Event 微服务一重启,事件直接丢失,不持久化!

1、会不会丢?

  • Spring Event 是内存事件
  • 存在 JVM 内存里
  • 服务重启、宕机、崩溃 → 未处理完的事件全部消失
  • 没有数据库、没有磁盘持久化
你刚 publish 事件,服务立刻重启👉 监听器还没执行,事件就没了提醒消息、站内信、推送直接漏发

2、同步 / 异步都会丢

  • 同步事件:执行完才结束事务,重启也丢
  • Spring 异步事件 @Async:重启必丢,非常容易漏消息

3、对比 MQ(RocketMQ/Kafka)

  • Spring Event:内存、重启丢失、不可回溯、仅限本服务
  • MQ:磁盘持久化、重启不丢、可重试、跨微服务

4、结合你案件提醒业务

你这个附件修改提醒、待办提醒业务要求绝对不能漏所以:
  • 内部解耦:用 Spring Event
  • 发消息、发短信、发推送:必须用 MQ

一句话总结

Spring Event 不持久化,微服务重启事件丢失,重要通知千万不能只用它!

-------------------------------------------------------------------------------------------------------------------

Spring 事件发布监听机制(Spring Event) 是本微服务监听实现还是另外的微服务

最关键结论(一句话)

Spring 事件发布监听机制(Spring Event) = 只能在【同一个微服务、同一个 JVM 进程内】使用,不能跨服务、不能跨微服务!

1. 明确区分

✅ Spring Event(你现在代码用的)

  • 范围:本服务内部
  • 作用:模块之间解耦(Controller → Service 之间)
  • 跨服务?不能!
  • 你那行代码:
    java
     
    运行
     
     
     
    publishEvent.publish(new RemindCreatedAfterEvent(...));
    
     
     
    只会被当前这个微服务里的监听器收到。

❌ 微服务之间通信(别的服务收不到)

如果要让另外的微服务接收消息,必须用:
  • MQ(RabbitMQ / RocketMQ / Kafka)
  • Spring Cloud Stream
  • Feign / HTTP 接口调用
Spring Event 完全做不到跨服务通信。

2. 用最简单的图告诉你区别

🔹 Spring Event(当前代码)

plaintext
 
 
[ 微服务A ]
   发布事件  →→→  本服务内部监听
   
[ 微服务B ]   (完全收不到)
 

🔹 微服务间通信(MQ)

plaintext
 
 
[ 微服务A ]  →→→  MQ中间件  →→→  [ 微服务B ]
 

3. 你现在的业务场景

你这行代码:
java
 
运行
 
 
 
// 发布提醒创建事件
this.publishEvent.publish(new RemindCreatedAfterEvent(lasReminderRecord));
 
作用:
  • 在当前这个服务内部,通知其他业务模块
  • 比如:发站内信、发推送、记录日志
  • 不会发给别的微服务

最终总结(必记)

  1. Spring Event = 单体 / 单个微服务内部事件机制
  2. 不能跨微服务、不能跨进程
  3. 如果你想让另外的微服务接收提醒 → 必须用 MQ 消息队列

-------------------------------------------------------------------------------------------------------------------

RESTful 风格什么样

超直白・RESTful 接口规范(一眼看懂,面试 + 开发通用)

1、核心一句话

URL 只写【资源名词】,不写动作;
 
用请求方式(GET/POST/PUT/DELETE)代表增删改查

2、标准 RESTful 长这样

① 查询所有

GET /lasReminderRecords

② 按条件搜索(你现在这种)

GET /lasReminderRecords?title=案件标题👉 这就是标准 RESTful!完全没问题

③ 根据 ID 查单个

GET /lasReminderRecords/{id}

④ 新增一条

POST /lasReminderRecords

⑤ 修改一条

PUT /lasReminderRecords/{id}

⑥ 删除一条

DELETE /lasReminderRecords/{id}

3、绝对不能写(非 RESTful 坏习惯)

路径里带动词、By、Query、Get
  • ❌ /getLasReminderRecord
  • ❌ /queryRecordByTitle
  • ❌ /lasReminderRecordByCase/中文
RESTful 规定:路径 = 资源动作 = 请求方式筛选条件 = ?xxx=xxx

4、你对比一下立刻懂

老式接口(不好)

GET /getReminderByCase/某某案件路径带动作、带条件、中文报错

RESTful 标准(你现在)

GET /lasReminderRecords?title=某某案件
  • 复数名词
  • GET = 查询
  • 条件拼接在问号后
  • 中文、特殊字符不会报错

5、极简口诀

  1. 路径只用复数名词
  2. 不写 get/add/update/delete
  3. 查条件用 ?参数
  4. 路径变量只用 ID,绝对不用中文
  5. GET 查、POST 增、PUT 改、DELETE 删

-------------------------------------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------------------------------------

posted @ 2026-04-21 08:41  hanease  阅读(4)  评论(0)    收藏  举报