JAVA | Guava EventBus 使用 发布/订阅模式的步骤
前言
EventBus是Guava的事件处理机制,是观察者模式(生产/消费模型)的一种实现。
观察者模式在我们日常开发中使用非常广泛,例如在订单系统中,订单状态或者物流信息的变更会向用户发送APP推送、短信、通知卖家、买家等等;审批系统中,审批单的流程流转会通知发起审批用户、审批的领导等等。
Observer模式也是JDK中自带就支持的,其在1.0版本就已经存在Observer,不过随着Java版本的飞速升级,其使用方式一直没有变化,许多程序库提供了更加简单的实现,例如GuavaEventBus、RxJava、EventBus等
一、为什么要用Observer模式以及EventBus优点?
EventBus优点
- 相比Observer编程简单方便
- 通过自定义参数可实现同步、异步操作以及异常处理
- 单进程使用,无网络影响
缺点
- 只能单进程使用
- 项目异常重启或者退出不保证消息持久化
如果需要分布式使用还是需要使用MQ
二、EventBus使用步骤
1.引入库
Gradle
compilegroup:'com.google.guava',name:'guava',version:'29.0-jre'
Maven
com.google.guava guava 29.0-jre
引入依赖后,这里我们主要使用com.google.common.eventbus.EventBus类进行操作,其提供了register、unregister、post来进行注册订阅、取消订阅和发布消息
publicvoidregister(Objectobject); publicvoidunregister(Objectobject); publicvoidpost(Objectevent);
2.同步使用
1.首先创建一个EventBus
EventBuseventBus=newEventBus();
2.创建一个订阅者
在GuavaEventBus中,是根据参数类型进行订阅,每个订阅的方法只能由一个参数,同时需要使用@Subscribe标识
classEventListener{ /** *监听Integer类型的消息 */ @Subscribe publicvoidlistenInteger(Integerparam){ System.out.println("EventListener#listenInteger->"+param); } /** *监听String类型的消息 */ @Subscribe publicvoidlistenString(Stringparam){ System.out.println("EventListener#listenString->"+param); } }
3.注册到EventBus上并发布消息
EventBuseventBus=newEventBus(); eventBus.register(newEventListener()); eventBus.post(1); eventBus.post(2); eventBus.post("3");
运行结果为
EventListener#listenInteger->1 EventListener#listenInteger->2 EventListener#listenString->3
根据需要我们可以创建多个订阅者完成订阅信息,同时如果一个类型存在多个订阅者,则所有订阅方法都会执行
为什么说这么做是同步的呢?
GuavaEvent实际上是使用线程池来处理订阅消息的,通过源码可以看出,当我们使用默认的构造方法创建EventBus的时候,其中executor为MoreExecutors.directExecutor(),其具体实现中直接调用的Runnable#run方法,使其仍然在同一个线程中执行,所以默认操作仍然是同步的,这种处理方法也有适用的地方,这样既可以解耦也可以让方法在同一个线程中执行获取同线程中的便利,比如事务的处理
EventBus部分源码
publicclassEventBus{ privatestaticfinalLoggerlogger=Logger.getLogger(EventBus.class.getName()); privatefinalStringidentifier; privatefinalExecutorexecutor; privatefinalSubscriberExceptionHandlerexceptionHandler; privatefinalSubscriberRegistrysubscribers; privatefinalDispatcherdispatcher; publicEventBus(){ this("default"); } publicEventBus(Stringidentifier){ this(identifier,MoreExecutors.directExecutor(),Dispatcher.perThreadDispatchQueue(),EventBus.LoggingHandler.INSTANCE); } publicEventBus(SubscriberExceptionHandlerexceptionHandler){ this("default",MoreExecutors.directExecutor(),Dispatcher.perThreadDispatchQueue(),exceptionHandler); } EventBus(Stringidentifier,Executorexecutor,Dispatcherdispatcher,SubscriberExceptionHandlerexceptionHandler){ this.subscribers=newSubscriberRegistry(this); this.identifier=(String)Preconditions.checkNotNull(identifier); this.executor=(Executor)Preconditions.checkNotNull(executor); this.dispatcher=(Dispatcher)Preconditions.checkNotNull(dispatcher); this.exceptionHandler=(SubscriberExceptionHandler)Preconditions.checkNotNull(exceptionHandler); } }
DirectExecutor部分源码
enumDirectExecutorimplementsExecutor{ INSTANCE; privateDirectExecutor(){ } publicvoidexecute(Runnablecommand){ command.run(); } publicStringtoString(){ return"MoreExecutors.directExecutor()"; } }
3.异步使用
通过上面的源码,可以看出只要将构造方法中的executor换成一个线程池实现即可,同时GuavaEventBus为了简化操作,提供了一个简化的方案即AsyncEventBus
EventBuseventBus=newAsyncEventBus(Executors.newCachedThreadPool());
这样即可实现异步使用
AsyncEventBus源码
publicclassAsyncEventBusextendsEventBus{ publicAsyncEventBus(Stringidentifier,Executorexecutor){ super(identifier,executor,Dispatcher.legacyAsync(),LoggingHandler.INSTANCE); } publicAsyncEventBus(Executorexecutor,SubscriberExceptionHandlersubscriberExceptionHandler){ super("default",executor,Dispatcher.legacyAsync(),subscriberExceptionHandler); } publicAsyncEventBus(Executorexecutor){ super("default",executor,Dispatcher.legacyAsync(),LoggingHandler.INSTANCE); } }
4.异常处理
如果处理时发生异常应该如何处理?在看源码中,无论是EventBus还是AsyncEventBus都可传入自定义的SubscriberExceptionHandler该handler当出现异常时会被调用,我可可以从参数exception获取异常信息,从context中获取消息信息进行特定的处理
其接口声明为
publicinterfaceSubscriberExceptionHandler{ /**Handlesexceptionsthrownbysubscribers.*/ voidhandleException(Throwableexception,SubscriberExceptionContextcontext); }
总结
在上面的基础上,我们可以定义一些消息类型来实现不同消息的监听和处理,通过实现SubscriberExceptionHandler来处理异常的情况,无论时同步还是异步都能游刃有余
参考
https://github.com/google/guava
https://github.com/greenrobot/EventBus
https://github.com/ReactiveX/RxJava
以上就是JAVA|GuavaEventBus使用发布/订阅模式的步骤的详细内容,更多关于GuavaEventBus使用发布/订阅模式的资料请关注毛票票其它相关文章!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。