📦 Spring事件监听器完整Demo
以下是一个完整的Spring Boot项目示例,演示@EventListener的多种用法。这个Demo模拟了一个电商订单系统,通过事件机制解耦订单创建后的各种处理逻辑。
项目结构
src/main/java/com/example/eventdemo/
├── EventDemoApplication.java # 启动类
├── config/
│ └── AsyncConfig.java # 异步配置
├── event/
│ ├── OrderCreatedEvent.java # 订单创建事件
│ ├── OrderPaidEvent.java # 订单支付事件
│ └── OrderCancelledEvent.java # 订单取消事件
├── model/
│ └── Order.java # 订单实体
├── service/
│ ├── OrderService.java # 订单服务
│ ├── EmailService.java # 邮件服务
│ ├── SmsService.java # 短信服务
│ ├── InventoryService.java # 库存服务
│ └── AuditService.java # 审计服务
└── controller/
└── OrderController.java # 订单控制器
1. 启动类和配置
java
// EventDemoApplication.java
@SpringBootApplication
@EnableAsync // 启用异步支持
public class EventDemoApplication {
public static void main(String[] args) {
SpringApplication.run(EventDemoApplication.class, args);
}
}
// AsyncConfig.java - 线程池配置
@Configuration
public class AsyncConfig {
@Bean("taskExecutor")
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(25);
executor.setThreadNamePrefix("EventListener-");
executor.initialize();
return executor;
}
}
2. 事件定义
java
// OrderCreatedEvent.java - 订单创建事件
public class OrderCreatedEvent {
private Long orderId;
private String customerName;
private String customerEmail;
private String customerPhone;
private BigDecimal amount;
private LocalDateTime createTime;
// 构造器、getter、setter
public OrderCreatedEvent(Long orderId, String customerName,
String customerEmail, String customerPhone,
BigDecimal amount) {
this.orderId = orderId;
this.customerName = customerName;
this.customerEmail = customerEmail;
this.customerPhone = customerPhone;
this.amount = amount;
this.createTime = LocalDateTime.now();
}
// getter 方法...
}
java
// OrderPaidEvent.java - 订单支付事件
public class OrderPaidEvent {
private Long orderId;
private String paymentMethod;
private LocalDateTime paidTime;
public OrderPaidEvent(Long orderId, String paymentMethod) {
this.orderId = orderId;
this.paymentMethod = paymentMethod;
this.paidTime = LocalDateTime.now();
}
// getter...
}
3. 服务类
java
// OrderService.java - 订单服务(事件发布者)
@Service
@Slf4j
public class OrderService {
@Autowired
private ApplicationEventPublisher eventPublisher;
public Order createOrder(String customerName, String email,
String phone, BigDecimal amount) {
log.info("1. 开始创建订单...");
// 模拟创建订单(实际应保存到数据库)
Order order = new Order();
order.setId(System.currentTimeMillis()); // 模拟ID
order.setCustomerName(customerName);
order.setCustomerEmail(email);
order.setCustomerPhone(phone);
order.setAmount(amount);
order.setStatus("CREATED");
order.setCreateTime(LocalDateTime.now());
log.info("2. 订单创建成功,订单号: {}", order.getId());
// 发布订单创建事件
eventPublisher.publishEvent(
new OrderCreatedEvent(order.getId(), customerName,
email, phone, amount)
);
log.info("3. 订单创建事件已发布,继续处理其他业务...");
return order;
}
public void payOrder(Long orderId, String paymentMethod) {
log.info("订单 {} 支付成功,支付方式: {}", orderId, paymentMethod);
// 发布订单支付事件
eventPublisher.publishEvent(
new OrderPaidEvent(orderId, paymentMethod)
);
}
}
4. 监听器实现(核心Demo)
java
// EmailListener.java - 邮件通知监听器
@Component
@Slf4j
public class EmailListener {
@Autowired
private EmailService emailService;
/**
* 监听订单创建事件,发送确认邮件
* 使用@Async实现异步发送,不阻塞主流程
*/
@EventListener
@Async("taskExecutor")
public void handleOrderCreated(OrderCreatedEvent event) {
log.info("[邮件监听器] 开始处理订单创建事件,订单号: {}", event.getOrderId());
try {
// 模拟邮件发送耗时
Thread.sleep(2000);
emailService.sendOrderConfirmation(
event.getCustomerEmail(),
event.getOrderId(),
event.getAmount()
);
log.info("[邮件监听器] 订单确认邮件已发送至: {}", event.getCustomerEmail());
} catch (InterruptedException e) {
log.error("[邮件监听器] 发送邮件失败", e);
}
}
/**
* 监听订单支付事件,发送支付成功邮件
* 条件:只有金额大于100的订单才发送详细邮件
*/
@EventListener(condition = "#event.orderId != null")
@Async
public void handleOrderPaid(OrderPaidEvent event) {
log.info("[邮件监听器] 处理订单支付事件,订单号: {}", event.getOrderId());
// 实际项目中,这里会根据orderId查询订单详情
emailService.sendPaymentSuccess(event.getOrderId());
}
}
java
// SmsListener.java - 短信通知监听器
@Component
@Slf4j
public class SmsListener {
@Autowired
private SmsService smsService;
/**
* 监听订单创建事件,发送短信通知
* 使用@Order指定执行顺序(数值越小优先级越高)
*/
@EventListener
@Order(1) // 优先于其他监听器执行
public void sendOrderSms(OrderCreatedEvent event) {
log.info("[短信监听器] 发送订单创建短信,订单号: {}", event.getOrderId());
smsService.sendOrderCreatedSms(
event.getCustomerPhone(),
event.getOrderId()
);
}
/**
* 监听订单支付事件,发送支付成功短信
* 演示泛型事件监听
*/
@EventListener
public void sendPaymentSms(Object event) {
if (event instanceof OrderPaidEvent) {
OrderPaidEvent paidEvent = (OrderPaidEvent) event;
log.info("[短信监听器] 发送支付成功短信,订单号: {}", paidEvent.getOrderId());
smsService.sendPaymentSuccessSms(paidEvent.getOrderId());
}
}
}
java
// InventoryListener.java - 库存监听器
@Component
@Slf4j
public class InventoryListener {
@Autowired
private InventoryService inventoryService;
/**
* 监听订单创建事件,扣减库存
* 使用try-catch确保不影响其他监听器
*/
@EventListener
@Order(2) // 在短信之后执行
public void deductInventory(OrderCreatedEvent event) {
log.info("[库存监听器] 开始扣减库存,订单号: {}", event.getOrderId());
try {
// 模拟库存扣减
boolean success = inventoryService.deductStock(event.getOrderId());
if (success) {
log.info("[库存监听器] 库存扣减成功");
} else {
log.warn("[库存监听器] 库存不足,订单号: {}", event.getOrderId());
}
} catch (Exception e) {
// 捕获异常,避免影响其他监听器
log.error("[库存监听器] 扣减库存失败", e);
}
}
}
java
// AuditListener.java - 审计监听器
@Component
@Slf4j
public class AuditListener {
@Autowired
private AuditService auditService;
/**
* 监听所有订单相关事件,记录审计日志
* 演示一个方法监听多个事件
*/
@EventListener
public void auditOrderEvent(Object event) {
if (event instanceof OrderCreatedEvent) {
OrderCreatedEvent createdEvent = (OrderCreatedEvent) event;
auditService.logOrderCreation(
createdEvent.getOrderId(),
createdEvent.getCustomerName(),
createdEvent.getAmount()
);
log.info("[审计监听器] 记录订单创建审计日志");
}
else if (event instanceof OrderPaidEvent) {
OrderPaidEvent paidEvent = (OrderPaidEvent) event;
auditService.logOrderPayment(
paidEvent.getOrderId(),
paidEvent.getPaymentMethod()
);
log.info("[审计监听器] 记录订单支付审计日志");
}
}
/**
* 监听订单创建事件,只处理大额订单(金额 > 1000)
* 使用SpEL表达式定义条件
*/
@EventListener(condition = "#event.amount.compareTo(1000) > 0")
public void handleLargeOrder(OrderCreatedEvent event) {
log.warn("[审计监听器] 大额订单警告!订单号: {}, 金额: {}",
event.getOrderId(), event.getAmount());
auditService.flagLargeOrder(event.getOrderId(), event.getAmount());
}
}
java
// StatisticsListener.java - 统计监听器
@Component
@Slf4j
public class StatisticsListener {
private final AtomicInteger orderCount = new AtomicInteger(0);
private final AtomicReference<BigDecimal> totalAmount =
new AtomicReference<>(BigDecimal.ZERO);
/**
* 监听订单创建事件,更新统计信息
* 演示有返回值的事件监听(返回值会作为新事件发布)
*/
@EventListener
public OrderStatisticsEvent updateStatistics(OrderCreatedEvent event) {
int count = orderCount.incrementAndGet();
BigDecimal amount = totalAmount.updateAndGet(
current -> current.add(event.getAmount())
);
log.info("[统计监听器] 订单统计更新: 总数={}, 总金额={}", count, amount);
// 返回一个新的事件,会被自动发布
return new OrderStatisticsEvent(count, amount);
}
/**
* 监听统计事件(由上一個监听器产生)
*/
@EventListener
public void handleStatistics(OrderStatisticsEvent event) {
log.info("[统计监听器] 收到统计事件: {}", event);
// 这里可以执行一些周期性统计任务
if (event.getOrderCount() % 10 == 0) {
log.info("[统计监听器] 已处理 {} 个订单,生成统计报表", event.getOrderCount());
}
}
// 内部统计事件类
public static class OrderStatisticsEvent {
private final int orderCount;
private final BigDecimal totalAmount;
public OrderStatisticsEvent(int orderCount, BigDecimal totalAmount) {
this.orderCount = orderCount;
this.totalAmount = totalAmount;
}
// getter...
}
}
5. 辅助服务类(模拟实现)
java
// EmailService.java
@Service
@Slf4j
public class EmailService {
public void sendOrderConfirmation(String email, Long orderId, BigDecimal amount) {
log.info("📧 发送订单确认邮件到: {}, 订单号: {}, 金额: {}", email, orderId, amount);
// 实际发送邮件逻辑
}
public void sendPaymentSuccess(Long orderId) {
log.info("📧 发送支付成功邮件,订单号: {}", orderId);
}
}
// SmsService.java
@Service
@Slf4j
public class SmsService {
public void sendOrderCreatedSms(String phone, Long orderId) {
log.info("📱 发送订单创建短信到: {}, 订单号: {}", phone, orderId);
}
public void sendPaymentSuccessSms(Long orderId) {
log.info("📱 发送支付成功短信,订单号: {}", orderId);
}
}
// InventoryService.java
@Service
@Slf4j
public class InventoryService {
public boolean deductStock(Long orderId) {
log.info("📦 扣减库存,订单号: {}", orderId);
// 模拟库存扣减,90%成功率
return Math.random() > 0.1;
}
}
// AuditService.java
@Service
@Slf4j
public class AuditService {
public void logOrderCreation(Long orderId, String customer, BigDecimal amount) {
log.info("📝 审计日志 - 订单创建: ID={}, 客户={}, 金额={}",
orderId, customer, amount);
}
public void logOrderPayment(Long orderId, String paymentMethod) {
log.info("📝 审计日志 - 订单支付: ID={}, 支付方式={}", orderId, paymentMethod);
}
public void flagLargeOrder(Long orderId, BigDecimal amount) {
log.info("⚠️ 大额订单标记: ID={}, 金额={}", orderId, amount);
}
}
6. 控制器(测试端点)
java
// OrderController.java
@RestController
@RequestMapping("/orders")
@Slf4j
public class OrderController {
@Autowired
private OrderService orderService;
@PostMapping("/create")
public ResponseEntity<Map<String, Object>> createOrder(
@RequestParam String customerName,
@RequestParam String email,
@RequestParam String phone,
@RequestParam BigDecimal amount) {
log.info("\n========== 收到创建订单请求 ==========");
log.info("客户: {}, 金额: {}", customerName, amount);
long startTime = System.currentTimeMillis();
// 创建订单(会触发事件)
Order order = orderService.createOrder(customerName, email, phone, amount);
long endTime = System.currentTimeMillis();
Map<String, Object> response = new HashMap<>();
response.put("success", true);
response.put("orderId", order.getId());
response.put("message", "订单创建成功");
response.put("processingTime", (endTime - startTime) + "ms");
response.put("note", "邮件/短信等通知正在异步处理中...");
log.info("订单创建完成,总处理时间: {}ms", (endTime - startTime));
log.info("========== 请求处理完成 ==========\n");
return ResponseEntity.ok(response);
}
@PostMapping("/{orderId}/pay")
public ResponseEntity<String> payOrder(
@PathVariable Long orderId,
@RequestParam String paymentMethod) {
orderService.payOrder(orderId, paymentMethod);
return ResponseEntity.ok("支付成功");
}
}
7. 模型类
java
// Order.java
@Data
public class Order {
private Long id;
private String customerName;
private String customerEmail;
private String customerPhone;
private BigDecimal amount;
private String status;
private LocalDateTime createTime;
}
8. 测试运行
方式一:使用cURL测试
bash
# 创建订单
curl -X POST "http://localhost:8080/orders/create?customerName=张三&email=zhangsan@example.com&phone=13800138000&amount=1500.50"
# 订单支付
curl -X POST "http://localhost:8080/orders/123456/pay?paymentMethod=ALIPAY"
方式二:使用单元测试
java
@SpringBootTest
@Slf4j
class OrderEventTests {
@Autowired
private OrderService orderService;
@Test
void testOrderCreatedEvent() {
log.info("测试开始...");
// 创建订单,会触发事件
Order order = orderService.createOrder(
"测试用户",
"test@example.com",
"13800138000",
new BigDecimal("2999.99")
);
// 等待异步事件处理完成
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("测试完成");
}
}
9. 预期输出效果
当你调用创建订单API时,控制台会输出:
========== 收到创建订单请求 ==========
客户: 张三, 金额: 1500.50
1. 开始创建订单...
2. 订单创建成功,订单号: 1646389471234
3. 订单创建事件已发布,继续处理其他业务...
[短信监听器] 发送订单创建短信,订单号: 1646389471234
📱 发送订单创建短信到: 13800138000, 订单号: 1646389471234
[库存监听器] 开始扣减库存,订单号: 1646389471234
📦 扣减库存,订单号: 1646389471234
[库存监听器] 库存扣减成功
[邮件监听器] 开始处理订单创建事件,订单号: 1646389471234
📧 发送订单确认邮件到: zhangsan@example.com, 订单号: 1646389471234, 金额: 1500.50
[邮件监听器] 订单确认邮件已发送至: zhangsan@example.com
[审计监听器] 记录订单创建审计日志
📝 审计日志 - 订单创建: ID=1646389471234, 客户=张三, 金额=1500.50
[审计监听器] 大额订单警告!订单号: 1646389471234, 金额: 1500.50
⚠️ 大额订单标记: ID=1646389471234, 金额=1500.50
[统计监听器] 订单统计更新: 总数=1, 总金额=1500.50
[统计监听器] 收到统计事件: OrderStatisticsEvent{orderCount=1, totalAmount=1500.50}
订单创建完成,总处理时间: 35ms
========== 请求处理完成 ==========
📌 Demo亮点总结
-
多种监听方式:
- 直接监听具体事件类型
- 使用
Object监听所有事件 - 使用SpEL条件表达式过滤
-
完整的事件处理特性:
@Async异步处理(邮件发送)@Order执行顺序控制- 异常处理不影响其他监听器
- 有返回值的事件链
-
实际业务场景:
- 订单创建后的多维度处理
- 大额订单特殊处理
- 审计日志记录
- 统计信息更新
-
架构价值体现:
- 主流程(订单创建)响应时间仅35ms
- 耗时操作(邮件发送2秒)异步处理
- 新增处理逻辑只需添加监听器,无需修改订单服务
这个Demo完整展示了@EventListener在生产环境中的典型应用,体现了事件驱动架构在解耦业务、提升性能方面的优势。