今天在看别人的代码时,看到Spring中事件发布publishEvent,所以特地查资料,学习一下,做个笔记。原文地址:Java 创建事件Event、事件监听EventListener、事件发布publishEvent_预立科技的博客-CSDN博客
一、概述
个人认为,事件机制一般可由:事件源source,事件对象Event,事件监听EventListener,事件发布publishEvent组成
事件源:引起事件发生的源; User用户信息, Order订单信息等为事件源数据,User登录状态loginStatus引起的事件, Order状态status引起的事件
事件对象:继承ApplicationEvent,事件对象包含事件源,事件对象也就是要被监听的对象; UserEvent, OrderEvent为事件对象,
事件监听:监听事件对象,事件对象被发布触发时,事件监听到后执行处理逻辑
事件发布:触发事件的发生
发布事件publishEvent后,EventListener监听到进行默认同步处理, 线程被阻塞, 这种同步方式吞吐量小耗时,不利用程序高并发。
在实际应用过程中,事件发布或事件监听后处理逻辑应该都是异步不阻塞线程。
publishEvent或EventListener 任意一个加上异步@Async即可(程序启动类必须要添加@EnableAsync)。推荐publishEvent加异步。
如果publishEven和EventListener过程中都有大量处理数据库或其他耗时的业务,也可以两者同时加上@Async
.
举例:
1.OrderEvent订单事件中,用户进行订单支付,订单支付逻辑处理完,同步返回给用户支付完成的消息,同时发布订单事件,异步处理订单发货逻辑等,这样可以将订单支付和订单发货解耦。
2.UserEvent用户事件中,用户登录成功后,同步返回给用户登录成功的消息,同时发布用户登录事件,异步处理用户登录后记日志登录日志, 写用户购物车缓存等逻辑
.
这种事件驱动机制其实是观察者模式(又称发布订阅)具体实现,事件对象(Event)相当于被观察对象(Subject), 事件监听(EventListener) 相当于观察者(Observer)
下面是简单的代码实现二、创建事件源
import lombok.Data;
@Data
public class User {
private Long id;
private String loginStatus;
}
package com.xxxx.model;
import lombok.Data;
@Data
public class Order {
private Long id;
private Integer status;
}
三、创建事件对象
例如:订单状态事件,用户状态事件, 需要继承ApplicationEvent
package com.xxxx.event;
import com.xxxx.model.Order;
import org.springframework.context.ApplicationEvent;
public class OrderEvent extends ApplicationEvent {
private Order order;
public OrderEvent(Order order) {
//ApplicationEvent 构造函数中必须传入source对象, 官方注释中被定义为最初发生事件的对象
super(order);
//方式二
//super(order.getId());
order = order;
}
public Order getOrder(){
return order;
}
}
四、事件监听
方法上添加监听事件的注解@EventListener
方法的参数为继承ApplicationEvent的事件对象
package com.xxxx.event;
import com.xxxx.model.Order;
import com.xxxx.model.User;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class EventListenerHandle {
/**
* EventListener 监听到OrderEvent事件,触发方法
* @param orderEvent
*/
@Async
@EventListener
public void handle(OrderEvent orderEvent){
Order order = orderEvent.getOrder();
//getSource() 取决去构建OrderEvent时的super(source)
//Object object = orderEvent.getSource();
//处理订单业务
if(order.getStatus() == 0){
}else (order.getStatus() == 1){
}else {
}
}
/**
* EventListener 监听到UserEvent事件,触发方法
* @param userEvent
*/
@Async
@EventListener
public void handle(UserEvent userEvent){
User user = userEvent.getUser();
//处理用户业务
if(user.getLoginStatus() == 0){
}else (user.getLoginStatus() == 1){
}else {
}
}
}
五、事件发布
ApplicationContext应用上下文继承了ApplicationEventPublisher,可以调用发布事件
package com.xxxx.event;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.stereotype.Component;
@Component
public class EventPush {
/**
* ApplicationContext 继承实现了 ApplicationEventPublisher, 可以直接发布事件
*/
@Autowired
private ApplicationContext applicationContext;
@Async
public void publishEvent(ApplicationEvent event){
if (event instanceof OrderEvent) {
applicationContext.publishEvent((OrderEvent) event);
return;
} else if(event instanceof UserEvent) {
applicationContext.publishEvent((UserEvent) event);
return;
} else {
//发布失败
}
}
@Async
public void orderEventPush(OrderEvent event){
applicationContext.publishEvent(event);
}
@Async
public void userEventPush(UserEvent event){
applicationContext.publishEvent(event);
}
}
六、调用
注入依赖类
@Autowired
private EventPush eventPush;
调用事件发布
Order order = new Order();
order.setId(1000L);
//0: 订单创建成功 1:支付成功 .....
order.setStatus(1);
User user = new User();
user.setId(1000L);
//0: 退出成功 1:登录成功 .....
user.setLoginStatus(1);
//方式一:
eventPush.orderEventPush(new OrderEvent(order));
eventPush.userEventPush(new UserEvent(user));
//方式二:
eventPush.publishEvent(new OrderEvent(order));
eventPush.publishEvent(new UserEvent(user));