說來慚愧,對應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