EventBus VS Spring Event
本文内容纲要:
-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("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<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条件
processmiaomiao'sCustomerEvent,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
- 使用方式比较
- 使用场景比较
本文内容总结:EventBusVSSpringEvent,GuavaEventBus,springevent,比较EventBus与SpringEvent,
原文链接:https://www.cnblogs.com/shoren/p/eventBus_springEvent.html