


























参考文章:
ApplicationContext 事件发布与监听机制详解
Spring ApplicationEventPublisher 事件发布
需求:
利用ApplicationContext的事件机制来完成下面的功能:
1. 订单创建
2. 接受订单,分配商家
3. 商家做好了,呼叫骑手
4. 骑手收到,开始送货
5. 收到外卖
代码实现如下:
1.代码结构:

2.事件event类:
package com.publish.event;
import org.springframework.context.ApplicationEvent;
/**
* @description com.publish.event
* @author: chengyu
* @date: 2026-01-15 20:54
*
* 当父类没有默认构造方法(无参构造器)时,所有子类(无论是抽象类还是具体类)都必须在自己的构造方法中显式调用父类的某个构造方法。
*
* 原因分析
* 在Java中,子类构造方法的第一行必须调用父类的构造方法(super(...))。
* 如果父类没有默认构造方法(无参构造器),编译器不会自动生成super()调用,此时必须显式调用。
*
* 当父类有构造方法时,子类的构造方法中不需要显式调用super(),因为编译器会自动添加
* 构造方法的调用规则与类是否是抽象类无关。只要父类没有默认构造器,所有子类都必须在自己的构造方法中显式调用父类的某个构造方法
*/
public abstract class OrderContextEvent<T> extends ApplicationEvent {
public OrderContextEvent(T source) {
super(source);
}
@Override
public T getSource() {
return (T) super.getSource();
}
}
package com.publish.event;
import com.publish.model.Order;
import lombok.Getter;
import lombok.Setter;
/**
* @description 订单创建事件
* @author: chengyu
* @date: 2026-01-15 20:15
*/
@Getter
@Setter
public class OrderCreatedEvent extends OrderContextEvent<Order>{
public OrderCreatedEvent(Order order) {
super(order);
}
}
package com.publish.event;
import com.publish.model.Order;
import com.publish.model.Rider;
import lombok.Getter;
import lombok.Setter;
/**
* @description 呼叫骑手事件
* @author: chengyu
* @date: 2026-01-15 20:21
*/
@Getter
@Setter
public class CallRiderEvent extends OrderContextEvent<Order> {
public CallRiderEvent(Order order) {
super(order);
}
}
package com.publish.event;
import com.publish.model.Rider;
import lombok.Getter;
import lombok.Setter;
/**
* @description 订单送达事件
* @author: chengyu
* @date: 2026-01-15 20:24
*/
@Getter
@Setter
public class OrderArrivedEvent extends OrderContextEvent<Rider>{
public OrderArrivedEvent(Rider rider) {
super(rider);
}
}
3.实体类:
package com.publish.model;
import lombok.Data;
/**
* @description com.publish.model
* @author: chengyu
* @date: 2026-01-15 21:05
*/
@Data
public class Order {
private String orderName;
private String customerName;
private String phone;
private String address;
private String message;
}
package com.publish.model;
import lombok.Data;
/**
* @description com.publish.model
* @author: chengyu
* @date: 2026-01-15 21:21
*/
@Data
public class Rider {
private Order order;
private String name;
private String age;
}
4.客户下单,订单创建发布事件:
package com.publish.controller;
import com.publish.event.OrderCreatedEvent;
import com.publish.model.Order;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @description com.publish.controller
* @author: chengyu
* @date: 2026-01-15 20:30
*/
@RestController
@RequestMapping("/order")
@Slf4j
public class OrderController {
@Autowired
private ApplicationContext applicationContext;
@GetMapping("/createOrder")
public String placeAnOrder() {
Order order = new Order();
order.setOrderName("煲仔饭");
order.setCustomerName("张三");
order.setPhone("13567678877");
order.setAddress("上海市浦东新区华胜天成小区1栋101");
order.setMessage("外卖放在家门口");
OrderCreatedEvent orderCreatedEvent = new OrderCreatedEvent(order);
applicationContext.publishEvent(orderCreatedEvent);
log.info("订单创建完成事件发布完成");
return "下单成功";
}
}
5.监听器:
商家接受外卖事件监听器,这里使用ApplicationEventPublisher来发布事件:
package com.publish.listener;
import com.publish.event.CallRiderEvent;
import com.publish.event.OrderCreatedEvent;
import com.publish.model.Order;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* @description 商家接受外卖事件监听器
* @author: chengyu
* @date: 2026-01-15 20:41
*/
@Component
@Slf4j
public class MerchantReceiveOrderListener implements ApplicationListener<OrderCreatedEvent> {
@Autowired
private ApplicationContext applicationContext;
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
/**
* listener监听事件:
* 实现方式1:实现 ApplicationListener 接口,重写onApplicationEvent方法
* 实现方式2:使用 @EventListener 注解
*/
@Override
@Async
public void onApplicationEvent(OrderCreatedEvent event) {
Order order = event.getSource();
log.info("商家收到订单:{}", order);
log.info("开始呼叫骑手...");
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
/**
* 使用applicationContext.publishEvent(new CallRiderEvent(order));也可以。
* 因为applicationContext实现了ApplicationEventPublisher接口
*/
applicationEventPublisher.publishEvent(new CallRiderEvent(order));
log.info("呼叫骑手事件发布完成" + System.lineSeparator());
}
}
package com.publish.listener;
import com.publish.event.CallRiderEvent;
import com.publish.event.OrderArrivedEvent;
import com.publish.model.Order;
import com.publish.model.Rider;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* @description 骑手接受呼叫骑手事件
* @author: chengyu
* @date: 2026-01-15 21:31
*/
@Component
@Slf4j
public class RiderReceiveOrderListener {
@Autowired
private ApplicationContext applicationContext;
@EventListener
@Async
public void handleCallRiderEvent(CallRiderEvent event) throws Exception {
Order order = event.getSource();
Rider rider = new Rider();
rider.setOrder(order);
rider.setAge("30");
rider.setName("饿了么潘伟");
log.info("骑手接到订单:{}", order);
log.info("骑手开始送货...");
TimeUnit.SECONDS.sleep(10);
applicationContext.publishEvent(new OrderArrivedEvent(rider));
log.info("订单送达事件发布完成" + System.lineSeparator());
}
}
package com.publish.listener;
import com.publish.event.OrderArrivedEvent;
import com.publish.model.Rider;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* @description 客户接受外卖送达事件
* @author: chengyu
* @date: 2026-01-15 21:41
*/
@Component
@Slf4j
public class CustomerReceiveOrderListener {
@EventListener
@Async
public void handleOrderArrivedEvent(OrderArrivedEvent event) throws InterruptedException {
Rider rider = event.getSource();
log.info("客户收到外卖,订单信息:{}", rider.getOrder());
log.info("骑手姓名:{},骑手年龄:{},请给个好评", rider.getName(), rider.getAge());
log.info("开始好好吃饭....");
TimeUnit.SECONDS.sleep(10);
log.info("吃完啦!" + System.lineSeparator());
}
}
测试:浏览器输入:http://localhost:8080/testHello/order/createOrder
马上显示:下单成功 可见是异步。
注意这里@Async注解的使用,上面例子中每个事件监听器上都有@Async注解,都是异步执行,发布完事件后立马方法结束,无需等待下个监听者执行完。
日志打印如下:
2026-03-15 11:55:29.988 INFO 9412 --- [nio-8080-exec-1] com.publish.controller.OrderController : 订单创建完成事件发布完成
2026-03-15 11:55:29.988 INFO 9412 --- [ task-1] c.p.l.MerchantReceiveOrderListener : 商家收到订单:Order(orderName=煲仔饭, customerName=张三, phone=13567678877, address=上海市浦东新区华胜天成小区1栋101, message=外卖放在家门口)
2026-03-15 11:55:29.989 INFO 9412 --- [ task-1] c.p.l.MerchantReceiveOrderListener : 开始呼叫骑手...
2026-03-15 11:55:40.001 INFO 9412 --- [ task-1] c.p.l.MerchantReceiveOrderListener : 呼叫骑手事件发布完成
2026-03-15 11:55:40.004 INFO 9412 --- [ task-2] c.p.listener.RiderReceiveOrderListener : 骑手接到订单:Order(orderName=煲仔饭, customerName=张三, phone=13567678877, address=上海市浦东新区华胜天成小区1栋101, message=外卖放在家门口)
2026-03-15 11:55:40.006 INFO 9412 --- [ task-2] c.p.listener.RiderReceiveOrderListener : 骑手开始送货...
2026-03-15 11:55:50.010 INFO 9412 --- [ task-2] c.p.listener.RiderReceiveOrderListener : 订单送达事件发布完成
2026-03-15 11:55:50.012 INFO 9412 --- [ task-3] c.p.l.CustomerReceiveOrderListener : 客户收到外卖,订单信息:Order(orderName=煲仔饭, customerName=张三, phone=13567678877, address=上海市浦东新区华胜天成小区1栋101, message=外卖放在家门口)
2026-03-15 11:55:50.013 INFO 9412 --- [ task-3] c.p.l.CustomerReceiveOrderListener : 骑手姓名:饿了么潘伟,骑手年龄:30,请给个好评
2026-03-15 11:55:50.013 INFO 9412 --- [ task-3] c.p.l.CustomerReceiveOrderListener : 开始好好吃饭....
2026-03-15 11:56:00.025 INFO 9412 --- [ task-3] c.p.l.CustomerReceiveOrderListener : 吃完啦!
但是一旦将RiderReceiveOrderListener、CustomerReceiveOrderListener上面的@Async注解注释掉,打印就不一样了:
2026-03-15 11:57:38.626 INFO 9064 --- [nio-8080-exec-1] com.publish.controller.OrderController : 订单创建完成事件发布完成
2026-03-15 11:57:38.626 INFO 9064 --- [ task-1] c.p.l.MerchantReceiveOrderListener : 商家收到订单:Order(orderName=煲仔饭, customerName=张三, phone=13567678877, address=上海市浦东新区华胜天成小区1栋101, message=外卖放在家门口)
2026-03-15 11:57:38.627 INFO 9064 --- [ task-1] c.p.l.MerchantReceiveOrderListener : 开始呼叫骑手...
2026-03-15 11:57:48.639 INFO 9064 --- [ task-1] c.p.listener.RiderReceiveOrderListener : 骑手接到订单:Order(orderName=煲仔饭, customerName=张三, phone=13567678877, address=上海市浦东新区华胜天成小区1栋101, message=外卖放在家门口)
2026-03-15 11:57:48.639 INFO 9064 --- [ task-1] c.p.listener.RiderReceiveOrderListener : 骑手开始送货...
2026-03-15 11:57:58.650 INFO 9064 --- [ task-1] c.p.l.CustomerReceiveOrderListener : 客户收到外卖,订单信息:Order(orderName=煲仔饭, customerName=张三, phone=13567678877, address=上海市浦东新区华胜天成小区1栋101, message=外卖放在家门口)
2026-03-15 11:57:58.651 INFO 9064 --- [ task-1] c.p.l.CustomerReceiveOrderListener : 骑手姓名:饿了么潘伟,骑手年龄:30,请给个好评
2026-03-15 11:57:58.651 INFO 9064 --- [ task-1] c.p.l.CustomerReceiveOrderListener : 开始好好吃饭....
2026-03-15 11:58:08.654 INFO 9064 --- [ task-1] c.p.l.CustomerReceiveOrderListener : 吃完啦!
2026-03-15 11:58:08.654 INFO 9064 --- [ task-1] c.p.listener.RiderReceiveOrderListener : 订单送达事件发布完成
2026-03-15 11:58:08.654 INFO 9064 --- [ task-1] c.p.l.MerchantReceiveOrderListener : 呼叫骑手事件发布完成
事件发布者必须等时间监听者执行完,方法才结束。所以上面每个listener上面都加了@Async
PS:
还可以增加订单状态:OrderStatus,每一次流转定义订单的状态:创建、商家接单、骑手接单、送货、已送达
注意:
(1) ApplicationContext.publishEvent 默认是同步操作, 并非发布后不管的异步操作,发布事件后需要等 @EventListener 执行完。
(2) 如果需要开启异步操作需要在@EventListener上增加@Async 注解。时间监听类通过 @Async 实现非阻塞事件处理。这样,当事件发布后,监听器的处理将会在一个新的线程中进行,不会阻塞事件发布者的执行。
(3) 启动类上增加@EnableAsync注解
如果多个Listener监听同一个事件,比如OrderCreatedEvent,需要控制多个监听器的执行顺序,可以使用 @Order 注解:
@Component
@Order(1)
class FirstOrderListener {
@EventListener
public void handleFirst(OrderCreatedEvent event) {
System.out.println("First listener for order: " + event.getOrderId());
}
}
@Component
@Order(2)
class SecondOrderListener {
@EventListener
public void handleSecond(OrderCreatedEvent event) {
System.out.println("Second listener for order: " + event.getOrderId());
}
}
--
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。