ApplicationContext 事件发布与监听机制详解

参考文章:

ApplicationContext 事件发布与监听机制详解

观察者 PublishEvent

Spring ApplicationEventPublisher 事件发布

 

需求:          

利用ApplicationContext的事件机制来完成下面的功能:
1. 订单创建
2. 接受订单,分配商家
3. 商家做好了,呼叫骑手
4. 骑手收到,开始送货
5. 收到外卖

 

代码实现如下:        

1.代码结构:    

image

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 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")
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);
        return "下单成功";
    }

}

5.监听器:    

商家接受外卖事件监听器:

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.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;

    @Override
    @Async
    public void onApplicationEvent(OrderCreatedEvent event) {
        Order order = event.getSource();
        log.info("商家收到订单:{}", order);
        log.info("开始呼叫骑手..." + System.lineSeparator());
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        applicationContext.publishEvent(new CallRiderEvent(order));
    }
}
骑手接受呼叫骑手事件:
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("骑手开始送货..." + System.lineSeparator());
        TimeUnit.SECONDS.sleep(10);
        applicationContext.publishEvent(new OrderArrivedEvent(rider));
    }
}
客户接受外卖送达事件:
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("开始好好吃饭...." + System.lineSeparator());
        TimeUnit.SECONDS.sleep(10);
        log.info("吃完啦!");
    }
}

测试:浏览器输入:http://localhost:8080/testHello/order/createOrder

马上显示:下单成功        可见是异步。

控制台打印:

2026-01-15 22:07:37.665  INFO 4280 --- [         task-4] c.p.l.MerchantReceiveOrderListener       : 商家收到订单:Order(orderName=煲仔饭, customerName=张三, phone=13567678877, address=上海市浦东新区华胜天成小区1栋101, message=外卖放在家门口)
2026-01-15 22:07:37.666  INFO 4280 --- [         task-4] c.p.l.MerchantReceiveOrderListener       : 开始呼叫骑手...

2026-01-15 22:07:42.678  INFO 4280 --- [         task-5] c.p.listener.RiderReceiveOrderListener   : 骑手接到订单:Order(orderName=煲仔饭, customerName=张三, phone=13567678877, address=上海市浦东新区华胜天成小区1栋101, message=外卖放在家门口)
2026-01-15 22:07:42.678  INFO 4280 --- [         task-5] c.p.listener.RiderReceiveOrderListener   : 骑手开始送货...

2026-01-15 22:07:52.693  INFO 4280 --- [         task-6] c.p.l.CustomerReceiveOrderListener       : 客户收到外卖,订单信息:Order(orderName=煲仔饭, customerName=张三, phone=13567678877, address=上海市浦东新区华胜天成小区1栋101, message=外卖放在家门口)
2026-01-15 22:07:52.693  INFO 4280 --- [         task-6] c.p.l.CustomerReceiveOrderListener       : 骑手姓名:饿了么潘伟,骑手年龄:30,请给个好评
2026-01-15 22:07:52.693  INFO 4280 --- [         task-6] c.p.l.CustomerReceiveOrderListener       : 开始好好吃饭....

2026-01-15 22:08:02.695  INFO 4280 --- [         task-6] c.p.l.CustomerReceiveOrderListener       : 吃完啦!

 

PS:        

还可以增加订单状态:OrderStatus,每一次流转定义订单的状态:创建、商家接单、骑手接单、送货、已送达

注意:
(1) ApplicationContext.publishEvent 默认是同步操作, 并非发布后不管的异步操作,发布事件后需要等 @EventListener 执行完。
(2) 如果需要开启异步操作需要在@EventListener上增加@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());
    }
}

 

 

 

 

 

 

 

--

posted on 2026-01-15 22:29  有点懒惰的大青年  阅读(2)  评论(0)    收藏  举报