Event Bus设计

模式实现:注解加服务者提供框架实现

三大要素:EventBus,Dispatcher,Registry

EventBus:提供对外部操作的方法。

Registry:用来整理所有在EventBus上注册的Subsriber(订购者)。

Dispatcher:负责对消息进行推送。

/**

* 定义Event Bus所使用的方法

*/

public interface Bus {



/**将某个对象注册到Bus上,从此该类就成为了subscribler了**/

void register(Object subsriber);



/**将某个对象从Bus上取消注册,取消注册之后就不会再接收到来自Bus的任何消息了**/

void unregister(Object suscriber);



/**提交event到默认的topic**/

void post(Object event);



/**提交event到指定的topic**/

void post(Object event,String topic);



/**关闭该bus**/

void close();



/**返回Bus的名称标识**/

String getBusName();

}



/**

* 消息推送出错时被回调接口EventExceptionHandler使用

*/

public interface EventContext {

String getSource();



Object getSubscriber();



Method getSubscribe();



Object getEvent();

}



public interface EventExceptionHandler {



void handle(Throwable cause,EventContext context);

}



/**

* 定义一个注解,只要一个属性topic

*

* Retention注解有一个属性value,是RetentionPolicy类型的,Enum RetentionPolicy是一个枚举类型,

* 这个枚举决定了Retention注解应该如何去保持,也可理解为Rentention 搭配 RententionPolicy使用。RetentionPolicy有3个值:CLASS RUNTIME SOURCE

* 用@Retention(RetentionPolicy.CLASS)修饰的注解,表示注解的信息被保留在class文件(字节码文件)中当程序编译时,但不会被虚拟机读取在运行的时候;

* 用@Retention(RetentionPolicy.SOURCE )修饰的注解,表示注解的信息会被编译器抛弃,不会留在class文件中,注解的信息只会留在源文件中;

* 用@Retention(RetentionPolicy.RUNTIME )修饰的注解,表示注解的信息被保留在class文件(字节码文件)中当程序编译时,会被虚拟机保留在运行时,

* 所以他们可以用反射的方式读取。RetentionPolicy.RUNTIME 可以让你从JVM中读取Annotation注解的信息,以便在分析程序的时候使用.

*/

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.METHOD)

public @interface Subscribe {

String topic() default "default-topic";



}



public class EventBus implements Bus{

/**

* 注册表

*/

private final Registry registry = new Registry();

/**

* event bus名字

*/

private String busName;



/**

* 默认event bus名字

*/

private final static String DEFAULT_BUS_NAME = "default";



/**

* 默认的topic名字

*/

private final static String DEFAULT_TOPIC = "default-topic";



/**

*用于分发广播消息到各个Subscriber的类

*/

private final Dispatcher dispatcher;



public EventBus(){

    this(DEFAULT_BUS_NAME,null,Dispatcher.SEQ_EXECUTOR_SETVICE);

}



public EventBus(String busName){

    this(busName,null,Dispatcher.SEQ_EXECUTOR_SETVICE);

}



EventBus(String busName, EventExceptionHandler eventExceptionHandler, Executor executor){

    this.busName = busName;

    this.dispatcher = Dispatcher.newDisPatcher(eventExceptionHandler,executor);

}



public EventBus(EventExceptionHandler eventExceptionHandler){

    this(DEFAULT_BUS_NAME,eventExceptionHandler,Dispatcher.SEQ_EXECUTOR_SETVICE);

}



@Override

public void register(Object subsriber) {

    this.registry.bind(subsriber);

}



@Override

public void unregister(Object suscriber) {

    this.registry.unbind(suscriber);

}



@Override

public void post(Object event) {

    this.post(event,DEFAULT_TOPIC);

}



@Override

public void post(Object event, String topic) {

    this.dispatcher.dispatch(this,registry,event,topic);

}



@Override

public void close() {

    this.dispatcher.close();

}



@Override

public String getBusName() {

    return this.busName;

}

}



public class AsyncEventBus extends EventBus{

AsyncEventBus(String busName, EventExceptionHandler eventExceptionHandler, ThreadPoolExecutor executor){

super(busName,eventExceptionHandler,executor);

}



public AsyncEventBus(String busName,ThreadPoolExecutor threadPoolExecutor){

super(busName,null,threadPoolExecutor);

}



public AsyncEventBus(ThreadPoolExecutor threadPoolExecutor){

this("default-async",null,threadPoolExecutor);

}



public AsyncEventBus(EventExceptionHandler eventExceptionHandler,ThreadPoolExecutor threadPoolExecutor){

this("default-async",eventExceptionHandler,threadPoolExecutor);

}

}





public class Dispatcher {



private final Executor executorService;



private final EventExceptionHandler eventExceptionHandler;



public static final Executor SEQ_EXECUTOR_SETVICE = SeqExecutorService.INSTANCE;



public static final Executor PRE_THREAD_EXECUTOR_SERVICE = PreThreadExecutorService.INSTANCE;



private Dispatcher(Executor executorService,EventExceptionHandler eventExceptionHandler){

this.executorService =executorService;

this.eventExceptionHandler = eventExceptionHandler;

}



public void dispatch(Bus bus,Registry registry,Object event,String topic){

ConcurrentLinkedQueue<Subscriber> subscribers = registry.scanSubscriber(topic);

if(null == subscribers){



if(eventExceptionHandler != null){

eventExceptionHandler.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 subscribeMethod = subscriber.getSubscribeMethod();

Class<?> aClass = subscribeMethod.getParameterTypes()[0];

return aClass.isAssignableFrom(event.getClass());



}).forEach(subscriber -> realInvokeSubscribe(subscriber,event,bus));

}



private void realInvokeSubscribe(Subscriber subscriber,Object event,Bus bus){

Method subscribeMethod = subscriber.getSubscribeMethod();

Object subscribeObject = subscriber.getSubscribeObject();



executorService.execute(() ->{

try {

subscribeMethod.invoke(subscribeObject,event);

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

if(null != eventExceptionHandler){

eventExceptionHandler.handle(e,new BaseEventContext(bus.getBusName(),subscriber,event));

}

}



});

}



public void close(){

if(executorService instanceof ExecutorService)

((ExecutorService)executorService).shutdown();

}



static Dispatcher newDisPatcher(EventExceptionHandler eventExceptionHandler,Executor executor){

return new Dispatcher(executor,eventExceptionHandler);

}



static Dispatcher seqDispatcher(EventExceptionHandler eventExceptionHandler){

return new Dispatcher(SEQ_EXECUTOR_SETVICE,eventExceptionHandler);

}



static Dispatcher preThreadDispatcher(EventExceptionHandler eventExceptionHandler){

return new Dispatcher(PRE_THREAD_EXECUTOR_SERVICE,eventExceptionHandler);

}



//顺序执行

private static class SeqExecutorService implements Executor{



private final static SeqExecutorService INSTANCE = new SeqExecutorService();

@Override

public void execute(Runnable command) {

command.run();

}

}

//每个线程负责一次消息推送

private static class PreThreadExecutorService implements Executor{

private final static PreThreadExecutorService INSTANCE = new PreThreadExecutorService();



@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 subscriber != null ? subscriber.getSubscribeObject():null;

}



@Override

public Method getSubscribe() {

return subscriber != null ? subscriber.getSubscribeMethod() : null;

}



@Override

public Object getEvent() {

return this.event;

}

}

}



/**

* 维护了topic和subscriber之间的关系,当有event被post之后,dispatcher需要该消息应发送到

* 那个Subscriber的实例和对应的方法

*/

public class Registry {



/**

* 用于存储topic与Subscriber之间的map

*/

private final ConcurrentHashMap<String, ConcurrentLinkedQueue<Subscriber>>

subscriberContainer = new ConcurrentHashMap<>();



public void bind(Object subscriber){

//获取Subscriber Object的方法集合然后进行绑定

List<Method> suscribeMethods = getSubscribeMethods(subscriber);



suscribeMethods.forEach(m -> tierSuscriber(subscriber,m));

}



public void unbind(Object subscriber){

subscriberContainer.forEach((key,queue)->queue.forEach(s->{

if(s.getSubscribeObject() == subscriber)

{

s.setDisable(true);

}

}));

}



public ConcurrentLinkedQueue<Subscriber> scanSubscriber(final String topic){

return subscriberContainer.get(topic);

}



private void tierSuscriber(Object subscriber,Method method){

final Subscribe subscribe = method.getDeclaredAnnotation(Subscribe.class);

String topic = subscribe.topic();

//如果不存在指定topic的queue,则创建一个

subscriberContainer.computeIfAbsent(topic,key -> new ConcurrentLinkedQueue<>());



//创建一个Subscriber并且加入Subscriber列表中

subscriberContainer.get(topic).add(new Subscriber(subscriber,method));

}



private List<Method> getSubscribeMethods(Object subsriber){

final List<Method> methods = new ArrayList<>();



Class<?> temp = subsriber.getClass();



while(temp != null){



Method[] declareMethods = temp.getDeclaredMethods();



//只有public方法,并且有一个入参&&被@Suscibe标记的方法才符合回调方法

Arrays.stream(declareMethods).filter(m -> m.isAnnotationPresent(Subscribe.class)

&& m.getParameterCount() == 1 && m.getModifiers() == Modifier.PUBLIC).

forEach(methods::add);

temp = temp.getSuperclass();

}

return methods;

}





}



public class Subscriber {

private final Object subscribeObject;



private final Method subscribeMethod;



private boolean disable = false;



public Subscriber(Object subscribeObject,Method subscribeMethod){

this.subscribeObject = subscribeObject;

this.subscribeMethod = subscribeMethod;

}



public Object getSubscribeObject(){

return subscribeObject;

}



public Method getSubscribeMethod(){

return subscribeMethod;

}



public boolean isDisable(){

return disable;

}



public void setDisable(boolean disable){

this.disable = disable;

}

}





public class SimpleSubscriber1 {



@Subscribe

public void method1(String message){

System.out.println("==SimpleSubscriber1==method1=="+message);

}



@Subscribe(topic = "test")

public void method2(String message){

System.out.println("==SimpleSubscriber1==method2=="+message);

}

}





public class EventBusTest {



public static void main(String args[]){

Bus bus = new EventBus("TestBus");

bus.register(new SimpleSubscriber1());

bus.register(new SimpleSubscriber2());



bus.post("hello");

System.out.println("-------");

bus.post("hello","test");

}



}

可以直接采用Guava的事件总线EventBus库,不需要自己写实现

发布了115 篇原创文章 · 获赞 57 · 访问量 20万+

猜你喜欢

转载自blog.csdn.net/qq_35211818/article/details/104186498
今日推荐