模式实现:注解加服务者提供框架实现
三大要素: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 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>
subscriberContainer = new ConcurrentHashMap<>();
public void bind(Object subscriber){
//获取Subscriber Object的方法集合然后进行绑定
List 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 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 getSubscribeMethods(Object subsriber){
final List 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库,不需要自己写实现