说来惭愧,对应Spring事件机制以前只知道实现 ApplicationListener 接口,就能够基于Spring自带的事件作一些事情(如ContextRefreshedEvent),可是最近看公司的wiki基于Spring事件的领域驱动才发现原来还有这么多东西。html
Spring是基于事件驱动模型的,咱们经常使用的MQ就是基于观察者模式设计的。
事件驱动模型也就是咱们常说的观察者,或者发布-订阅模型;理解它的几个关键点:java
Java API实现和自定义实现观察者模式:git
Java提供了两个接口java.util.Observable和java.util.Observer,代码可参考https://github.com/2YSP/design-pattern/tree/master/src/cn/sp/observergithub
具体表明者是:ApplicationEventPublisher及ApplicationEventMulticaster,系统默认提供了以下实现:spring
ApplicationListener 接口提供了onApplicationEvent方法,可是咱们须要在该方法实现内部判断事件类型来处理,也没有提供按顺序触发监听器的语义,因此Spring提供了另外一个接口,SmartApplicationListener:bash
public interface SmartApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {
//若是实现支持该事件类型 那么返回true
boolean supportsEventType(Class<? extends ApplicationEvent> eventType);
//若是实现支持“目标”类型,那么返回true
boolean supportsSourceType(Class<?> sourceType);
//顺序,即监听器执行的顺序,值越小优先级越高
int getOrder();
}
源码分析到这里,下面说说怎么使用。app
场景是咱们保存一个订单后发布事件通知,以便作一些其余操做好比锁定商品。
订单实体类:框架
public class Order {
private String orderNo;
private String orderStatus;
private String goods;
private Date createTime;
//省略get、set、toString方法
}
订单建立事件OrderCreateEvent异步
public class OrderCreateEvent extends ApplicationEvent {
private final Order order;
public OrderCreateEvent(Object source,Order order) {
super(source);
this.order = order;
}
public Order getOrder(){
return order;
}
}
OrderServiceide
监听器OrderCreateEventListener
运行测试类:
@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationEventDemoApplicationTests {
@Autowired
OrderService orderService;
@Test
public void contextLoads() {
orderService.save();
}
}
控制台打印以下则表示成功实现了监听。
订单保存成功:Order{orderNo='20190601983801', orderStatus='待付款', goods='手机', createTime=Sat Jun 01 00:23:58 CST 2019}
2019-06-01 00:23:58.069 INFO 15060 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
cn.sp.listener.OrderCreateEventListener -- ApplicationListener 接口实现,订单号[20190601983801]:,锁定商品[手机]
================
接着上面的,自定义的监听器必定要实现ApplicationListener接口吗?不是,Spring还提供了注解的方式 @EventListener,使用示例以下:
@Component
public class OrderCreateEventListenerAnnotation {
@EventListener
public void createOrderEvent(OrderCreateEvent event){
System.out.println(this.getClass().getName()+"--订单建立事件,@EventListener注解实现,orderNo:"+event.getOrder().getOrderNo());
}
}
注意:@EventListener有个condition属性,还能够支持条件判断(定义布尔SpEL表达式),只有知足条件才会触发,后面泛型支持那里有示例。
上面的监听事件都是同步触发的,若是想异步的怎么办?
只须要两步:
@Async
@EventListener
public void createOrderEvent(OrderCreateEvent event){
System.out.println(this.getClass().getName()+"--订单建立事件,@EventListener注解实现,orderNo:"+event.getOrder().getOrderNo());
}
事件类必定要继承ApplicationEvent吗?
固然不是,咱们还能够自定义泛型类实现事件调度(这个是我认为最厉害的地方了)。
/** * 能够自定义泛型类实现事件调度 * Created by 2YSP on 2019/5/30. */
public class GenericEvent<T> {
private T data;
private boolean success;
public GenericEvent(T data,boolean success){
this.data = data;
this.success = success;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
}
public class OrderGenericEvent extends GenericEvent<Order> {
public OrderGenericEvent(Order data, boolean success) {
super(data, success);
}
}
applicationEventPublisher.publishEvent(new OrderGenericEvent(order,true));
@Component
public class OrderGenericEventListener {
@EventListener(condition = "#event.success")
public void orderListener(GenericEvent<Order> event){
System.out.println(this.getClass().getName()+"--处理泛型条件事件。。。");
}
}
测试结果代表,成功处理了事件。
当咱们监听一个事件处理完成时,还须要发布另外一个事件,通常咱们想到的是调用ApplicationEventPublisher#publishEvent发布事件方法,但Spring提供了另外一种更加灵活的新的事件继续传播机制,监听方法返回一个事件,也就是方法的返回值就是一个事件对象。
示例代码:
public void save(){
String orderNo = getOrderNo();
Order order = new Order();
order.setOrderNo(orderNo);
order.setOrderStatus("待付款");
order.setCreateTime(new Date());
order.setGoods("手机");
System.out.println("订单保存成功:" + order.toString());
//发布事件
// applicationEventPublisher.publishEvent(new OrderCreateEvent(this,order));
applicationEventPublisher.publishEvent(order);
// applicationEventPublisher.publishEvent(new OrderGenericEvent(order,true));
System.out.println("================");
}
订单监听器
@Component
public class OrderListener {
@EventListener
public void orderListener(Order order){
System.out.println(this.getClass().getName() + " -- 监听一个订单");
}
@EventListener
public OrderCreateEvent orderReturnEvent(Order order){
System.out.println(this.getClass().getName() + " -- 监听一个订单,返回一个新的事件 OrderCreateEvent");
return new OrderCreateEvent(this,order);
}
}
启动单元测试,就会发现OrderCreateEventListener也被触发了。
从Spring 4.2开始,框架提供了一个新的@TransactionalEventListener注解,它是@EventListener的扩展,容许将事件的侦听器绑定到事务的一个阶段。绑定能够进行如下事务阶段:
@TransactionalEventListener(phase = BEFORE_COMMIT)
public void txEvent(Order order) {
System.out.println("事物监听");
}
上面代码的意思是仅当存在事件生成器正在运行且即将提交的事务时,才会调用此侦听器。而且,若是没有正在运行的事务,则根本不发送事件,除非咱们经过将fallbackExecution 属性设置为true来覆盖它 ,即 @TransactionalEventListener(fallbackExecution = true)。
基于事件驱动模型能够很方便的实现解耦,提升代码的可读性和可维护性,代码地址:https://github.com/2YSP/application-event-demo
疑问: 泛型支持那里若是不写一个类继承通用泛型事件,就跑不通这是为何呢?
若是有人知道请告诉我,很是感谢。
参考:https://blog.csdn.net/sun_shaoping/article/details/84067446