Spring Event 是 Spring 框架内置的事件/监听器机制,是观察者模式的一种实现。它允许一个组件(发布者)发布一个事件,而其他一个或多个组件(监听器)可以订阅并响应该事件,而发布者和监听者之间没有直接的类依赖。
实现下面的实例:工人提交了维修工单后 ①发送邮件给维修站点师傅、②如果提交的是停机维修则要修改设备为停机、③增加一个操作记录
创建一个 springboot 项目,导入 web 坐标用来实现访问接口
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
启动类中添加 @EnableAsync
注解
@SpringBootApplication
@EnableAsync
public class BootEventProjectApplication {
public static void main(String[] args) {
SpringApplication.run(BootEventProjectApplication.class, args);
}
}
创建一个 dataobject 来模拟数据库的 DO
import lombok.Data;
@Data
public class WorkOrderDO {
private String code;
private String submitter;
private String description;
/**
* 是否为停机维修
*/
private Boolean isStop;
}
创建一个RepairOrderEvent
类继承 ApplicationEvent
类
ApplicationEvent
是Spring 框架中的一个核心类,用于实现事件驱动的应用程序。它是一个抽象类,用于发布和监听事件,是 Spring 中事件机制的基础。
import com.runbrick.event.dataobject.WorkOrderDO;
import lombok.Getter;
import lombok.ToString;
import org.springframework.context.ApplicationEvent;
@Getter
@ToString
public class RepairOrderEvent extends ApplicationEvent {
private WorkOrderDO workOrderDO;
public RepairOrderEvent(Object source) {
super(source);
}
public RepairOrderEvent(Object source, WorkOrderDO workOrderDO) {
super(source);
this.workOrderDO = workOrderDO;
}
}
实现 ①发送邮件给维修站点师傅、②如果提交的是停机维修则要修改设备为停机、③增加一个操作记录 这三个 Listener
用来实现在提交报修的时候来执行这几个操作
import com.runbrick.event.event.RepairOrderEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
/**
* 设备停机处理监听器
*/
@Slf4j
@Component
public class ShutdownListener {
/**
* 通过条件判断是否执行停机处理
* @param event
*/
@EventListener(condition = "#event.workOrderDO.isStop == true ")
@Async
public void equipmentShutdown(RepairOrderEvent event) {
log.info("[repair][设备停机处理]");
}
}
import com.runbrick.event.event.RepairOrderEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
/**
* 发送邮件
*/
@Slf4j
@Component
public class RepairEmailListener implements ApplicationListener<RepairOrderEvent> {
@Override
@Async
public void onApplicationEvent(RepairOrderEvent event) {
log.info("[onApplicationEvent][给用户({}) 发送邮件:{}]", event.getWorkOrderDO().getSubmitter(), event.getWorkOrderDO().getDescription());
}
}
import com.runbrick.event.event.RepairOrderEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class LogListener implements ApplicationListener<RepairOrderEvent> {
@Override
@Async
@Order(10)
public void onApplicationEvent(RepairOrderEvent event) {
log.info("[log][记录用户({}) 的提报逻辑]", event.getWorkOrderDO());
}
}
注:
- 实现监听器有两种方式一种是直接
implements ApplicationListener
另一种是 通过注解 @EventListener
的方式 。 这两种方式都可以,不过我更推荐使用注解的方式来实现 - 通过
@Order()
可以实现 Listener 顺序 - 通过
@EnableAsync
和 @Async
实现异步,这是最主要的内容。通过 @Async
可以实现基于内存的消息队列的功能 - 在
@EventListener()
增加判断条件 condition = "#event.workOrderDO.isStop == true "
。用 SpEL 表达式来决定是否执行该监听器
创建一个 Controller 用来测试数据是否是我想的那样
import com.runbrick.event.dataobject.WorkOrderDO;
import com.runbrick.event.publisher.RepairService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/repair")
@AllArgsConstructor
@Slf4j
public class RepairController {
private RepairService repairService;
/**
* 提交维修工单
*/
@PostMapping("/submit")
public void submit(@RequestBody WorkOrderDO workOrderDO) {
repairService.submit(workOrderDO); // 提交工单
log.info("[repair][提交工单成功]");
}
}
通过 IDEA 提交测试
- 测试非停机
###
POST http://localhost:18080/repair/submit
Content-Type: application/json
{
"code": "30021",
"submitter": "张三",
"description": "设备出问题了",
"isStop": false
}
2025-06-26T13:44:36.855+08:00 INFO 33352 --- [io-18080-exec-2] c.r.event.publisher.RepairService : [repair][执行用户(WorkOrderDO(code=30021, submitter=张三, description=设备出问题了, isStop=false)) 的提报逻辑]
2025-06-26T13:44:36.857+08:00 INFO 33352 --- [io-18080-exec-2] c.r.event.controller.RepairController : [repair][提交工单成功]
2025-06-26T13:44:36.857+08:00 INFO 33352 --- [ task-6] c.runbrick.event.listener.LogListener : [log][记录用户(WorkOrderDO(code=30021, submitter=张三, description=设备出问题了, isStop=false)) 的提报逻辑]
2025-06-26T13:44:36.857+08:00 INFO 33352 --- [ task-7] c.r.event.listener.RepairEmailListener : [onApplicationEvent][给用户(张三) 发送邮件:设备出问题了]
2025-06-26T17:02:37.155+08:00 INFO 33352 --- [io-18080-exec-7] c.r.event.publisher.RepairService : [repair][执行用户(WorkOrderDO(code=30021, submitter=张三, description=设备出问题了, isStop=false)) 的提报逻辑]
2025-06-26T17:02:37.163+08:00 INFO 33352 --- [ task-8] c.runbrick.event.listener.LogListener : [log][记录用户(WorkOrderDO(code=30021, submitter=张三, description=设备出问题了, isStop=false)) 的提报逻辑]
2025-06-26T17:02:37.163+08:00 INFO 33352 --- [ task-9] c.r.event.listener.RepairEmailListener : [onApplicationEvent][给用户(张三) 发送邮件:设备出问题了]
2025-06-26T17:02:37.166+08:00 INFO 33352 --- [io-18080-exec-7] c.r.event.controller.RepairController : [repair][提交工单成功]
- 测试停机
###
POST http://localhost:18080/repair/submit
Content-Type: application/json
{
"code": "30021",
"submitter": "张三",
"description": "设备出问题了",
"isStop": true
}
2025-06-26T17:03:17.885+08:00 INFO 33352 --- [io-18080-exec-8] c.r.event.publisher.RepairService : [repair][执行用户(WorkOrderDO(code=30021, submitter=张三, description=设备出问题了, isStop=true)) 的提报逻辑]
2025-06-26T17:03:17.886+08:00 INFO 33352 --- [ task-10] c.runbrick.event.listener.LogListener : [log][记录用户(WorkOrderDO(code=30021, submitter=张三, description=设备出问题了, isStop=true)) 的提报逻辑]
2025-06-26T17:03:17.886+08:00 INFO 33352 --- [ task-11] c.r.event.listener.RepairEmailListener : [onApplicationEvent][给用户(张三) 发送邮件:设备出问题了]
2025-06-26T17:03:17.886+08:00 INFO 33352 --- [io-18080-exec-8] c.r.event.controller.RepairController : [repair][提交工单成功]
2025-06-26T17:03:17.887+08:00 INFO 33352 --- [ task-12] c.r.event.listener.ShutdownListener : [repair][设备停机处理]
从这两个测试来看证明 在 @EventListener()
增加判断条件 condition = "#event.workOrderDO.isStop == true "
是可以的。