EventBus与Spring Event区别详解(EventBus 事件机制,Spring Event事件机制)
本地异步处理,采用事件机制可以使代码解耦,更易读。事件机制实现模式是观察者模式(或发布订阅模式),主要分为三部分:发布者、监听者、事件。
GuavaEventBus
GuavaEventBus实现是观察者模式,用法很简单,先上代码。
/** *Desc:事件对象 */ @Data @NoArgsConstructor @AllArgsConstructor publicclassHelloEvent{ privateStringeventName; } @Data @NoArgsConstructor publicclassWorldEventextendsHelloEvent{ privateinteventNo; publicWorldEvent(Stringname,intno){ setEventName(name); setEventNo(no); } } /** *Desc:事件监听器,可以监听多个事件。处理方法添加@Subscribe注解即可。 */ publicclassGeventListener{ /** *监听HelloEvent类型及其父类型(Object)的事件 */ @Subscribe publicvoidprocessEvent(HelloEventevent){ System.out.println("processhelloevent,name:"+event.getEventName()); } /** *监听WorldEvent类型及其父类型(HelloEvent和Object)的事件 */ @Subscribe publicvoidprocessWorldEvent(WorldEventevent){ System.out.println("processworldeventV1,no:"+event.getEventNo()+",name:"+event.getEventName()); } /** *注册多个监听器监听同一事件 *@paramevent */ @Subscribe publicvoidprocessWorldEventV2(WorldEventevent){ System.out.println("processworldeventV2,no:"+event.getEventNo()+",name:"+event.getEventName()); } @Subscribe publicvoidprocessObject(Objectobject){ System.out.println("processcommonevent,class:"+object.getClass().getSimpleName()); } } publicclassGuavaTest{ publicstaticvoidmain(String[]args){ EventBuseventBus=newEventBus(); GeventListenerlistener=newGeventListener(); eventBus.register(listener); eventBus.post(newHelloEvent("hello")); eventBus.post(newWorldEvent("world",23333)); } }
结果如下:
//HelloEvent被两个监听器处理(HelloEvent类及Object类的监听器) processhelloevent,name:hello processcommonevent,class:HelloEvent //WorldEvent被四个监听器处理(两个自己的,两个父类的) processworldeventV1,no:23333,name:world processworldeventV2,no:23333,name:world processhelloevent,name:world processcommonevent,class:WorldEvent
由上可知:GuavaEventBus把类当做事件,是以class为key注册和管理事件的,value是事件监听器的method;事件监听器只处理某一类(及其父类)事件。
事件注册与发布
//com.google.common.eventbus.EventBus#register publicvoidregister(Objectobject){ //key为Class,value为EventSubscriber(Objecttarget,Methodmethod)【集合】。注意这里Multimap为HashMultimap,即HashMap> Multimap ,EventSubscriber>methodsInListener= finder.findAllSubscribers(object); subscribersByTypeLock.writeLock().lock(); try{ subscribersByType.putAll(methodsInListener); }finally{ subscribersByTypeLock.writeLock().unlock(); } } //com.google.common.eventbus.EventBus#post publicvoidpost(Objectevent){ //找到event类及其所有父类 Set >dispatchTypes=flattenHierarchy(event.getClass()); booleandispatched=false; for(Class>eventType:dispatchTypes){ subscribersByTypeLock.readLock().lock(); try{ //找到所有事件订阅者(事件监听器) Set wrappers=subscribersByType.get(eventType); if(!wrappers.isEmpty()){ dispatched=true; for(EventSubscriberwrapper:wrappers){ //事件入队列 enqueueEvent(event,wrapper); } } }finally{ subscribersByTypeLock.readLock().unlock(); } } //如果没有订阅者订阅此类消息,则为DeadEvent if(!dispatched&&!(eventinstanceofDeadEvent)){ post(newDeadEvent(this,event)); } dispatchQueuedEvents(); }
事件隔离
多个EventBus可以隔离事件。
publicclassAnotherListener{ /** *监听WorldEvent类型及其父类型(HelloEvent和Object)的事件 */ @Subscribe publicvoidprocessAnotherWorldEvent(WorldEventevent){ System.out.println("processanotherworldevent,no:"+event.getEventNo()+",name:"+event.getEventName()); } } publicclassGuavaTest{ publicstaticvoidmain(String[]args){ EventBuseventBus=newEventBus(); GeventListenerlistener=newGeventListener(); eventBus.register(listener); eventBus.post(newHelloEvent("hello")); EventBusanotherEventBus=newEventBus(); AnotherListeneranotherListener=newAnotherListener(); anotherEventBus.register(anotherListener); anotherEventBus.post(newWorldEvent("AnotherWorld",666)); } }
结果是
//eventBus结果与之前相同 processhelloevent,name:hello //anotherEventBus发布的事件,只被其注册的监听器处理 processcommonevent,class:HelloEvent processanotherworldevent,no:666,name:AnotherWorld
适用场景:
- 按照类区分事件
- 订阅事件簇
- 支持自定义event,可以根据event自己写分发器
- 事件隔离
springevent
spring新版事件机制也比较简单,看代码。
/** *继承ApplicationEvent的事件 */ @Data publicclassHelloEventextendsApplicationEvent{ privateStringeventName; publicHelloEvent(StringeventName){ super(eventName); setEventName(eventName); } } /** *自定义事件 */ @Data @NoArgsConstructor @AllArgsConstructor publicclassCustomerEvent{ privateStringname; privateBooleanisCustomer; } /** *监听器类,spring也支持一个类中监听多个事件 */ @Component("springListener") publicclassSpringListener{ /** *监听所有ApplicationEvent类型及其子类型的事件 */ @EventListener publicvoidprocessApplicationEvent(ApplicationEventevent){ System.out.println("processcommonevent,class:"+event.getClass().getSimpleName()); } /** *监听HelloEvent类型事件 */ @EventListener publicvoidprocessHelloEvent(HelloEventevent){ System.out.println("processhelloEvent,name:"+event.getEventName()); } /** *监听CustomerEvent类型事件,但是需要满足condition条件,即isCustomer=true */ @EventListener(condition="#event.isCustomer") publicvoidprocessCustomerEvent(CustomerEventevent){ System.out.println("processcustomerCustomerEvent,name:"+event.getName()); } /** *监听CustomerEvent类型事件,但是需要满足condition条件,即name="miaomiao" */ @EventListener(condition="#event.getName().equals('miaomiao')") publicvoidprocessMiaoMiaoEvent(CustomerEventevent){ System.out.println("processmiaomiao'sCustomerEvent,name:"+event.getName()); } /** *支持异步处理事件 */ @Async @EventListener publicvoidprocessAsyncCustomerEvent(CustomerEventevent){ System.out.println("AsyncprocessCustomerEvent,name:"+event.getName()); } } //执行类,测试入口 @SpringBootApplication @ComponentScan(basePackages={"com.example.manyao.async"}) publicclassDemoApplication{ publicstaticvoidmain(String[]args)throwsTException{ SpringApplication.run(DemoApplication.class,args); ApplicationContextcontext=newClassPathXmlApplicationContext("applicationContext.xml"); String[]names=context.getBeanDefinitionNames(); for(inti=0;i结果是
//以下是spring上下文event,继承自ApplicationContextEvent。用于用户参与上下文生命周期的入口。因为是ApplicationEvent子类型,所以,由processApplicationEvent处理。 processcommonevent,class:ContextRefreshedEvent processcommonevent,class:EmbeddedServletContainerInitializedEvent processcommonevent,class:ApplicationReadyEvent processcommonevent,class:ContextRefreshedEvent //以下是上下文中的bean springListener org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalRequiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory ++++++++++ //HelloEvent继承ApplicationEvent,会被processApplicationEvent处理 processcommonevent,class:HelloEvent //监听HelloEvent类型的processHelloEvent处理 processhelloEvent,name:helloEvent //非ApplicationEvent的事件,则为PayloadApplicationEvent processcommonevent,class:PayloadApplicationEvent //isCustomer=true,符合processCustomerEvent处理条件 processcustomerCustomerEvent,name:customer //监听CustomerEvent类型,处理结果 AsyncprocessCustomerEvent,name:customer processcommonevent,class:PayloadApplicationEvent //符合processMiaoMiaoEvent条件 processmiaomiao'sCustomerEvent,name:miaomiao AsyncprocessCustomerEvent,name:miaomiao //spring上下文事件 processcommonevent,class:ContextClosedEventspring上下文事件
上述例子中的
ContextRefreshedEvent,EmbeddedServletContainerInitializedEvent,ApplicationReadyEvent,ContextRefreshedEvent,ContextClosedEvent等事件,都是spring上下文事件。可以通过监听这些事件,参与到spring生命周期中去。这种无侵入性交互方式,在做平台服务时,是一种很好的方式。
注册监听器
org.springframework.context.event.EventListenerMethodProcessor#processBean将所有注解EventListener的方法,存入上下文的applicationListeners中。Listener的封装类为ApplicationListenerMethodAdapter(StringbeanName,Class>targetClass,Methodmethod)。
org.springframework.context.support.AbstractApplicationContext#refresh中调用initApplicationEventMulticaster初始化事件发布管理器applicationEventMulticaster,然后调用registerListeners()注册监听器。
发布事件
spring起初只支持ApplicationEvent类型事件,后来优化之后,支持自定义事件。自定义事件的处理,默认为PayloadApplicationEvent,相当于EventBus的DeadEvent。
//org.springframework.context.support.AbstractApplicationContext#publishEvent(java.lang.Object,org.springframework.core.ResolvableType) protectedvoidpublishEvent(Objectevent,ResolvableTypeeventType){ Assert.notNull(event,"Eventmustnotbenull"); if(logger.isTraceEnabled()){ logger.trace("Publishingeventin"+getDisplayName()+":"+event); } //DecorateeventasanApplicationEventifnecessary ApplicationEventapplicationEvent; if(eventinstanceofApplicationEvent){ applicationEvent=(ApplicationEvent)event; } else{ //若不是ApplicationEvent类型,则使用PayloadApplicationEvent封装 applicationEvent=newPayloadApplicationEvent执行事件
@Override publicvoidmulticastEvent(finalApplicationEventevent,ResolvableTypeeventType){ ResolvableTypetype=(eventType!=null?eventType:resolveDefaultEventType(event)); //获取事件的监听器集合,并逐个触发执行监听器 for(finalApplicationListener>listener:getApplicationListeners(event,type)){ //异步的话,就放在线程池中执行 Executorexecutor=getTaskExecutor(); if(executor!=null){ executor.execute(newRunnable(){ @Override publicvoidrun(){ invokeListener(listener,event); } }); } else{ //本线程调用 invokeListener(listener,event); } } }可以看到,spring的事件机制更复杂,但是功能同样强大。
适用场景:
- 按照类区分事件
- 订阅事件簇
- 支持自定义event
- 按照condition过滤同类型事件
比较EventBus与SpringEvent
使用方式比较
项目 事件 发布者 发布方法 是否异步 监听者 注册方式 EventBus 任意对象 EventBus EventBus#post 是 注解Subscribe方法 手动注册EventBus#register SpringEvent 任意对象 ApplicationEventPublisher ApplicationEventPublisher#publishEvent 支持同步异步 注解EventListener方法 系统注册 使用场景比较
项目 事件区分 是否支持事件簇 是否支持自定义event 是否支持过滤 是否支持事件隔离 复杂程度 EventBus Class 是 是 否 是 简单 SpringEvent Class 是 是 是 否 复杂 更多关于EventBus与SpringEvent文章大家可查看下面的相关链接
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。