觀察者模式:定義對象間一種一對多的依賴關係,使得每當一個對象改變狀態,所有依賴它的對象都會得到通知並自動更新。
Guava框架中的EventBus(事件總線)是對觀察者模式的一種實現。
EventBus是在單體架構內實現的松耦合的絕佳方式,通過它可以很簡潔的實現事件註冊監聽和消費。
Guava框架中提供了EventBus(同步)和AsyncEventBus(異步,繼承於EventBus)兩種時間總線:
1.單線程同步事件消費
2.多線程異步事件消費
Guava默認訂閱者的消費方法不具有併發能力,如果你的消費方法具有併發能力,可以使用@AllowConcurrentEvents註解,用來標記當前訂閱者是線程安全的,支持併發接收事件消息。
訂閱方法(被@Subscribe修飾的方法)的參數類型與事件發佈者一致時,將會接收到消息並消費。若事件發佈者post的某個事件沒有被訂閱,那麼改時間將會被修飾爲DeadEvent,並被對應的DeadEvent訂閱者接收處理。
import com.google.common.eventbus.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @ClassName: EventBusTest
* @Description: TODO
* @Author: RuiXin Yu
* @Date: 2019/9/19 20:59
*/
public class EventBusTest {
private static class Event1 {
@Override
public String toString() {
return "事件1";
}
}
private static class Event2 {
@Override
public String toString() {
return "事件2";
}
}
private static class EventX {
@Override
public String toString() {
return "事件X";
}
}
private static class EventListener {
@Subscribe
@AllowConcurrentEvents
public void onEvent(Event1 event1) throws InterruptedException {
String name = Thread.currentThread().getName();
System.out.println(name + " sleep 一會兒");
Thread.sleep(1000);
System.out.println(name + "===訂閱事件1,接收到:" + event1);
}
@Subscribe
public void onEvent(Event2 event2) throws InterruptedException {
String name = Thread.currentThread().getName();
System.out.println(name + " sleep 一會兒");
Thread.sleep(1000);
System.out.println(name + "===訂閱事件2,接收到:" + event2);
}
@Subscribe
public void onEvent(DeadEvent deadEvent) throws InterruptedException {
String name = Thread.currentThread().getName();
Thread.sleep(10*1000);
System.out.println(name + "===訂閱錯誤的事件,接收到:" + deadEvent);
}
}
public static void main(String[] args) throws InterruptedException {
String name = Thread.currentThread().getName();
EventBus eb = new EventBus();
eb.register(new EventListener());
System.out.println(name + "----------發送事件X---------");
eb.post(new EventX());
System.out.println(name + "----------發送事件1----並行接收-----");
ExecutorService threadPool = Executors.newCachedThreadPool();
eb = new AsyncEventBus(threadPool);
eb.register(new EventListener());
for (int i = 0; i < 10; i++) {
eb.post(new Event1());
}
Thread.sleep(2000);
System.out.println(name + "----------發送事件2----串行接收-----");
for (int i = 0; i < 10; i++) {
eb.post(new Event2());
}
Thread.sleep(2000);
threadPool.shutdown();
}
}
控制檯打印
main----------發送事件X---------
main===訂閱錯誤的事件,接收到:DeadEvent{source=EventBus{default}, event=事件X}
main----------發送事件1---------
pool-1-thread-1 sleep 一會兒
pool-1-thread-2 sleep 一會兒
pool-1-thread-3 sleep 一會兒
pool-1-thread-4 sleep 一會兒
pool-1-thread-5 sleep 一會兒
pool-1-thread-6 sleep 一會兒
pool-1-thread-7 sleep 一會兒
pool-1-thread-8 sleep 一會兒
pool-1-thread-9 sleep 一會兒
pool-1-thread-10 sleep 一會兒
pool-1-thread-1===訂閱事件1,接收到:事件1
pool-1-thread-2===訂閱事件1,接收到:事件1
pool-1-thread-3===訂閱事件1,接收到:事件1
pool-1-thread-4===訂閱事件1,接收到:事件1
pool-1-thread-5===訂閱事件1,接收到:事件1
pool-1-thread-7===訂閱事件1,接收到:事件1
pool-1-thread-6===訂閱事件1,接收到:事件1
pool-1-thread-8===訂閱事件1,接收到:事件1
pool-1-thread-9===訂閱事件1,接收到:事件1
pool-1-thread-10===訂閱事件1,接收到:事件1
main----------發送事件2---------
pool-1-thread-9 sleep 一會兒
pool-1-thread-9===訂閱事件2,接收到:事件2
pool-1-thread-2 sleep 一會兒
pool-1-thread-2===訂閱事件2,接收到:事件2
pool-1-thread-5 sleep 一會兒
pool-1-thread-5===訂閱事件2,接收到:事件2
pool-1-thread-3 sleep 一會兒
pool-1-thread-3===訂閱事件2,接收到:事件2
pool-1-thread-4 sleep 一會兒
pool-1-thread-4===訂閱事件2,接收到:事件2
pool-1-thread-1 sleep 一會兒
pool-1-thread-1===訂閱事件2,接收到:事件2
pool-1-thread-7 sleep 一會兒
pool-1-thread-7===訂閱事件2,接收到:事件2
pool-1-thread-6 sleep 一會兒
pool-1-thread-6===訂閱事件2,接收到:事件2
pool-1-thread-8 sleep 一會兒
pool-1-thread-8===訂閱事件2,接收到:事件2
pool-1-thread-10 sleep 一會兒
pool-1-thread-10===訂閱事件2,接收到:事件2
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* @ClassName: EventBusTest
* @Description: TODO
* @Author: Yu RuiXin
* @Date: 2020/1/20 17:27
*/
public class EventBusTest {
static void sendPost(EventBus eb, String appId, String bizCode, String bizSubCode,String data) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
EventTypeEnum eventTypeEnum = EventTypeEnum.valueOf(appId, bizCode, bizSubCode);
Constructor constructor = eventTypeEnum.eventClass.getConstructor(String.class);
Object event = constructor.newInstance(data);
eb.post(event);
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
EventBus eb = new EventBus();
eb.register(new EventListener());
sendPost(eb,"1","11","111","這是數據啊");
sendPost(eb,"x","xx","xxx","這是數據啊");
sendPost(eb,"2","22","222","這是數據啊");
}
enum EventTypeEnum {
EVENT1("1", "11", "111", Event1.class),
EVENT2("2", "22", "222", Event2.class),
EVENT3("x", "xx", "xxx", EventX.class),
;
private String appId;
private String bizCode;
private String bizSubCode;
private Class eventClass;
EventTypeEnum(String appId, String bizCode, String bizSubCode, Class eventClass) {
this.appId = appId;
this.bizCode = bizCode;
this.bizSubCode = bizSubCode;
this.eventClass = eventClass;
}
public static EventTypeEnum valueOf(String appId, String bizCode, String bizSubCode) {
for (EventTypeEnum t : EventTypeEnum.values()) {
if (t.appId.equals(appId) && t.bizCode.equals(bizCode) && t.bizSubCode.equals(bizSubCode)) {
return t;
}
}
return null;
}
}
@Data
@AllArgsConstructor
static class Event {
String data;
}
static class Event1 extends Event {
public Event1(String data) {
super(data);
}
}
static class Event2 extends Event {
public Event2(String data) {
super(data);
}
}
static class EventX extends Event {
public EventX(String data) {
super(data);
}
}
private static class EventListener {
@Subscribe
public void onEvent(Event1 event1) {
System.out.println("事件1:"+event1.getData());
}
@Subscribe
public void onEvent(Event2 event2) {
System.out.println("事件2:"+event2.getData());
}
@Subscribe
public void onEvent(EventX eventX) {
System.out.println("事件3:"+eventX.getData());
}
}
}