Event Bus设计模式

EventBus是消息中间件的设计思想,在此设计中有三个非常重要的角色(Bus、Registry、Dispatcher),Bus主要负责提供给外部使用的操作方法;Registry注册表用来整理记录所有注册在EventBus上的Subscriber;Dispatcher主要负责对Subscriber消息进行推送(用反射的方式执行方法),考虑到程序的灵活性,Dispatcher方法也提供了Executor的多态方式。

示例代码如下:

java 复制代码
public interface Bus {
void register(Object subscriber);
void unregister(Object subscriber);
void post(Object event);
void post(Object event,String topic);
void close();
String getBusName();
}
java 复制代码
import java.lang.reflect.Method;

public interface EventContext {
String getSource();
Object getSubscriber();
Method getSubscribe();
Object getEvent();
}
java 复制代码
public interface EventExceptionHandler {
void handle(Throwable cause,EventContext context);
}
java 复制代码
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Retention(RUNTIME)
@Target(METHOD)
public @interface Subscribe {
String topic() default "default-topic";
}
java 复制代码
public class Subscriber {
private final Object subscribeObject;
private final Object subscribeMethod;
private boolean disable=false;

public Subscriber(Object subscribeObject,Object subscribeMethod) {
this.subscribeObject=subscribeObject;
this.subscribeMethod=subscribeMethod;
}

public Object getSubscribeObject() {
return subscribeObject;
}

public Object getSubscribeMethod() {
return subscribeMethod;
}

public boolean isDisable() {
return disable;
}

public void setDisable(boolean disable) {
this.disable = disable;
}
}
java 复制代码
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;


class Registry {
private final ConcurrentHashMap<String,ConcurrentLinkedQueue<Subscriber>> subscriberContainer=new ConcurrentHashMap<>();

private List<Method> getSubscribeMethods(Object subscriber){
final List<Method> methods=new ArrayList<>();
Class<?> type=subscriber.getClass();
while(type!=null) {
Method[] declaredMethods=type.getDeclaredMethods();
Arrays.stream(declaredMethods).filter(m->m.isAnnotationPresent(Subscribe.class)
&&m.getParameterCount()==1
&&m.getModifiers()==Modifier.PUBLIC)
.forEach(methods::add);
type=type.getSuperclass();
}
return methods;
}

private void tierSubscriber(Object subscriber,Method method) {
final Subscribe subscribe=method.getDeclaredAnnotation(Subscribe.class);
String topic=subscribe.topic();
this.subscriberContainer.computeIfAbsent(topic, key->new ConcurrentLinkedQueue());
this.subscriberContainer.get(topic).add(new Subscriber(subscriber,method));
}

public void bind(Object subscriber) {
List<Method> subscribeMethods=getSubscribeMethods(subscriber);
subscribeMethods.forEach(m->tierSubscriber(subscriber,m));
}

public void unbind(Object subscriber) {
this.subscriberContainer.forEach((key,queue)->queue.forEach(s->{
if(s.getSubscribeObject()==subscriber) {
s.setDisable(true);
}
}));
}

public ConcurrentLinkedQueue<Subscriber> scanScriber(String topic) {
return this.subscriberContainer.get(topic);
}
}
java 复制代码
import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;

public class Dispatcher {
private final Executor executorService;
private final EventExceptionHandler exceptionHandler;
public static final Executor SEQ_EXECUTOR_SERVICE=SeqExecutorService.INSTANCE;
public static final Executor PER_THREAD_EXECUTOR_SERVICE=PerThreadExecutorService.INSTANCE;

private Dispatcher(Executor executorService,EventExceptionHandler handler) {
this.executorService=executorService;
this.exceptionHandler=handler;
}

private void realInvokeSubscribe(Subscriber subscriber,Object event,Bus bus) {
Method method=(Method) subscriber.getSubscribeMethod();
Object object=subscriber.getSubscribeObject();
this.executorService.execute(()->{
try {
method.invoke(object, event);
} catch (Exception e) {
if(null!=exceptionHandler) {
exceptionHandler.handle(e, new BaseEventContext(bus.getBusName(),subscriber,event));
}
e.printStackTrace();
}
});
}

public void dispatch(Bus bus, Registry registry,Object event, String topic) {
ConcurrentLinkedQueue<Subscriber> subscribers=registry.scanScriber(topic);
if(null==subscribers) {
if(exceptionHandler!=null) {
exceptionHandler.handle(new IllegalArgumentException("The topic "+topic+" not bind yet"),
new BaseEventContext(bus.getBusName(),null,event));
}
return ;
}
subscribers.stream().filter(subscriber->!subscriber.isDisable())
.filter(subscriber->{
Method method=(Method) subscriber.getSubscribeMethod();
Class<?> aClass=method.getParameterTypes()[0];
return (aClass.isAssignableFrom(event.getClass()));
}).forEach(subscriber->this.realInvokeSubscribe(subscriber, event, bus));
}

public void close() {
if(this.executorService instanceof ExecutorService) {
((ExecutorService)this.executorService).shutdown();
}
}

static Dispatcher newDispatcher(EventExceptionHandler handler,Executor executor) {
return new Dispatcher(executor,handler);
}

static Dispatcher seqDispatcher(EventExceptionHandler handler) {
return new Dispatcher(SEQ_EXECUTOR_SERVICE,handler);
}

static Dispatcher perThreadDispatcher(EventExceptionHandler handler) {
return new Dispatcher(PER_THREAD_EXECUTOR_SERVICE,handler);
}

private static class SeqExecutorService implements Executor{
private final static SeqExecutorService INSTANCE=new SeqExecutorService();
@Override
public void execute(Runnable command) {
command.run();
}
}

private static class PerThreadExecutorService implements Executor{
private final static PerThreadExecutorService INSTANCE=new PerThreadExecutorService();
@Override
public void execute(Runnable command) {
new Thread(command).start();
}
}

private static class BaseEventContext implements EventContext{
private final String eventBusName;
private final Subscriber subscriber;
private final Object event;
private BaseEventContext(String eventBusName,Subscriber subscriber,Object event) {
this.eventBusName=eventBusName;
this.subscriber=subscriber;
this.event=event;
}
@Override
public String getSource() {
return this.eventBusName;
}

@Override
public Object getSubscriber() {
return this.subscriber!=null?subscriber.getSubscribeObject():null;
}

@Override
public Method getSubscribe() {
return this.subscriber==null?(Method)subscriber.getSubscribeMethod():null;
}

@Override
public Object getEvent() {
return this.event;
}
}
}
java 复制代码
import java.util.concurrent.Executor;

public class EventBus implements Bus{
private final Registry resitry=new Registry();
private String busName;
private static final String DEFAULT_BUS_NAME="default";
private static final String DEFAULT_TOPIC="default-topic";
private final Dispatcher dispatcher;

public EventBus() {
this(DEFAULT_BUS_NAME,null,Dispatcher.SEQ_EXECUTOR_SERVICE);
}

public EventBus(String busName) {
this(busName,null,Dispatcher.SEQ_EXECUTOR_SERVICE);
}

EventBus(String busName,EventExceptionHandler handler,Executor executor){
this.busName=busName;
this.dispatcher=Dispatcher.newDispatcher(handler, executor);
}

public EventBus(EventExceptionHandler exceptionHandler) {
this(DEFAULT_BUS_NAME,exceptionHandler,Dispatcher.SEQ_EXECUTOR_SERVICE);
}

@Override
public void register(Object subscriber) {
this.resitry.bind(subscriber);
}

@Override
public void unregister(Object subscriber) {
this.resitry.unbind(subscriber);
}

@Override
public void post(Object event) {
this.post(event,DEFAULT_TOPIC);
}

@Override
public void post(Object event, String topic) {
this.dispatcher.dispatch(this, resitry, event, topic);
}

@Override
public void close() {
this.dispatcher.close();
}

@Override
public String getBusName() {
return this.busName;
}

}
java 复制代码
import java.util.concurrent.ThreadPoolExecutor;

public class AsyncEventBus extends EventBus{

AsyncEventBus(String busName,EventExceptionHandler handler,ThreadPoolExecutor executor){
super(busName,handler,executor);
}

public AsyncEventBus(String busName,ThreadPoolExecutor threadPoolExecutor) {
this(busName, null, threadPoolExecutor);
}

public AsyncEventBus(ThreadPoolExecutor executor) {
this("default-async",null,executor);
}

public AsyncEventBus(EventExceptionHandler handler,ThreadPoolExecutor executor) {
this("default-async",handler,executor);
}
}
java 复制代码
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

public class SimpleScriberTest {

@Subscribe
public void methodA(String message) {
System.out.println("==SimpleSubscriber==methodA=="+message);
}

@Subscribe(topic="test")
public void methodB(String message) {
System.out.println("==SimpleSubscriber==methodB=="+message);
}

public static void main(String[] args) {
//Bus bus=new EventBus("TestBus");
Bus bus=new AsyncEventBus("TestBus",(ThreadPoolExecutor)Executors.newFixedThreadPool(10));
bus.register(new SimpleScriberTest());
bus.post("Hello");
System.out.println("__________________");
bus.post("Hello", "test");
}

}
相关推荐
时来天地皆同力.13 分钟前
Java面试基础:概念
java·开发语言·jvm
找不到、了40 分钟前
Spring的Bean原型模式下的使用
java·spring·原型模式
阿华的代码王国1 小时前
【Android】搭配安卓环境及设备连接
android·java
YuTaoShao1 小时前
【LeetCode 热题 100】141. 环形链表——快慢指针
java·算法·leetcode·链表
铲子Zzz2 小时前
Java使用接口AES进行加密+微信小程序接收解密
java·开发语言·微信小程序
霖檬ing2 小时前
K8s——配置管理(1)
java·贪心算法·kubernetes
Vic101013 小时前
Java 开发笔记:多线程查询逻辑的抽象与优化
java·服务器·笔记
Biaobiaone3 小时前
Java中的生产消费模型解析
java·开发语言
特立独行的猫a3 小时前
11款常用C++在线编译与运行平台推荐与对比
java·开发语言·c++
louisgeek3 小时前
Java 位运算
java