首页 文章资讯内容详情

EventBus VS Spring Event

2026-06-01 4 花语

本文内容纲要:

-EventBusVSSpringEvent -GuavaEventBus -springevent -比较EventBus与SpringEvent

EventBusVSSpringEvent

本地异步处理,采用事件机制可以使代码解耦,更易读。事件机制实现模式是观察者模式(或发布订阅模式),主要分为三部分:发布者、监听者、事件。

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<K,Collection<V>> Multimap<Class<?>,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<Class<?>>dispatchTypes=flattenHierarchy(event.getClass()); booleandispatched=false; for(Class<?>eventType:dispatchTypes){ subscribersByTypeLock.readLock().lock(); try{ //找到所有事件订阅者(事件监听器) Set<EventSubscriber>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("processmiaomiaosCustomerEvent,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<names.length;i++){ System.out.println(names[i]); } System.out.println("++++++++++"); context.publishEvent(newHelloEvent("helloEvent")); context.publishEvent(newCustomerEvent("customer",true)); context.publishEvent(newCustomerEvent("miaomiao",false)); } }

结果是

//以下是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条件 processmiaomiaosCustomerEvent,name:miaomiao AsyncprocessCustomerEvent,name:miaomiao //spring上下文事件 processcommonevent,class:ContextClosedEvent spring上下文事件

上述例子中的

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<Object>(this,event); if(eventType==null){ eventType=((PayloadApplicationEvent)applicationEvent).getResolvableType(); } } //Multicastrightnowifpossible-orlazilyoncethemulticasterisinitialized if(this.earlyApplicationEvents!=null){ this.earlyApplicationEvents.add(applicationEvent); } else{ //核心操作,初始化event getApplicationEventMulticaster().multicastEvent(applicationEvent,eventType); } //调用父类,发布事件 //Publisheventviaparentcontextaswell... if(this.parent!=null){ if(this.parentinstanceofAbstractApplicationContext){ ((AbstractApplicationContext)this.parent).publishEvent(event,eventType); } else{ this.parent.publishEvent(event); } } } 执行事件 @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 是 是 是 否 复杂

本文内容总结:EventBusVSSpringEvent,GuavaEventBus,springevent,比较EventBus与SpringEvent,

原文链接:https://www.cnblogs.com/shoren/p/eventBus_springEvent.html