溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

EventBus與SpringEvent的區(qū)別是什么

發(fā)布時(shí)間:2021-10-15 16:05:56 來源:億速云 閱讀:142 作者:柒染 欄目:編程語言

EventBus與SpringEvent的區(qū)別是什么,相信很多沒有經(jīng)驗(yàn)的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個(gè)問題。

Guava EventBus

Guava EventBus實(shí)現(xiàn)是觀察者模式,用法很簡單,先上代碼。

/** * Desc: 事件對象 */@Data@NoArgsConstructor@AllArgsConstructorpublic class HelloEvent {  private String eventName;}  @Data@NoArgsConstructorpublic class WorldEvent extends HelloEvent {   private int eventNo;   public WorldEvent(String name, int no) {    setEventName(name);    setEventNo(no);  }} /** * Desc: 事件監(jiān)聽器,可以監(jiān)聽多個(gè)事件。處理方法添加 @Subscribe 注解即可。 */public class GeventListener {   /**   * 監(jiān)聽 HelloEvent 類型及其父類型(Object)的事件   */  @Subscribe  public void processEvent(HelloEvent event){    System.out.println("process hello event, name:" + event.getEventName());  }   /**   * 監(jiān)聽 WorldEvent 類型及其父類型(HelloEvent 和 Object)的事件   */  @Subscribe  public void processWorldEvent(WorldEvent event) {    System.out.println("process world eventV1, no:" + event.getEventNo() + ", name:" + event.getEventName());  }  /**   * 注冊多個(gè)監(jiān)聽器 監(jiān)聽同一事件   * @param event   */  @Subscribe  public void processWorldEventV2(WorldEvent event) {    System.out.println("process world eventV2, no:" + event.getEventNo() + ", name:" + event.getEventName());  }   @Subscribe  public void processObject(Object object) {    System.out.println("process common event, class:" + object.getClass().getSimpleName());  }} public class GuavaTest {   public static void main(String[] args) {    EventBus eventBus = new EventBus();    GeventListener listener = new GeventListener();    eventBus.register(listener);     eventBus.post(new HelloEvent("hello"));    eventBus.post(new WorldEvent("world", 23333));  }}

結(jié)果如下:

//HelloEvent被兩個(gè)監(jiān)聽器處理(HelloEvent類及Object類的監(jiān)聽器)process hello event, name:helloprocess common event, class:HelloEvent//WorldEvent被四個(gè)監(jiān)聽器處理(兩個(gè)自己的,兩個(gè)父類的)process world eventV1, no:23333, name:worldprocess world eventV2, no:23333, name:worldprocess hello event, name:worldprocess common event, class:WorldEvent

由上可知:Guava EventBus把類當(dāng)做事件,是以class為key注冊和管理事件的,value是事件監(jiān)聽器的method;事件監(jiān)聽器只處理某一類(及其父類)事件。

事件注冊與發(fā)布

//com.google.common.eventbus.EventBus#register public void register(Object object) { //key為Class, value為EventSubscriber(Object target, Method method)【集合】。注意這里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 public void post(Object event) {   //找到event類及其所有父類  Set<Class<?>> dispatchTypes = flattenHierarchy(event.getClass());  boolean dispatched = false;  for (Class<?> eventType : dispatchTypes) {   subscribersByTypeLock.readLock().lock();   try {   //找到所有事件訂閱者(事件監(jiān)聽器)    Set<EventSubscriber> wrappers = subscribersByType.get(eventType);    if (!wrappers.isEmpty()) {     dispatched = true;     for (EventSubscriber wrapper : wrappers) {     //事件入隊(duì)列      enqueueEvent(event, wrapper);     }    }   } finally {    subscribersByTypeLock.readLock().unlock();   }  }//如果沒有訂閱者訂閱此類消息,則為 DeadEvent  if (!dispatched && !(event instanceof DeadEvent)) {   post(new DeadEvent(this, event));  }  dispatchQueuedEvents(); }

事件隔離

多個(gè)EventBus可以隔離事件。

public class AnotherListener {  /**   * 監(jiān)聽 WorldEvent 類型及其父類型(HelloEvent 和 Object)的事件   */  @Subscribe  public void processAnotherWorldEvent(WorldEvent event) {    System.out.println("process another world event, no:" + event.getEventNo() + ", name:" + event.getEventName());  }}public class GuavaTest {  public static void main(String[] args) {    EventBus eventBus = new EventBus();    GeventListener listener = new GeventListener();    eventBus.register(listener);    eventBus.post(new HelloEvent("hello"));    EventBus anotherEventBus = new EventBus();    AnotherListener anotherListener = new AnotherListener();    anotherEventBus.register(anotherListener);    anotherEventBus.post(new WorldEvent("AnotherWorld", 666));  }}

結(jié)果是

//eventBus結(jié)果與之前相同process hello event, name:hello//anotherEventBus 發(fā)布的事件,只被其注冊的監(jiān)聽器處理process common event, class:HelloEventprocess another world event, no:666, name:AnotherWorld

適用場景:

  1. 按照類區(qū)分事件  訂閱 事件簇  支持自定義event,可以根據(jù)event自己寫分發(fā)器  事件隔離

spring event

spring 新版事件機(jī)制也比較簡單,看代碼。

/** * 繼承 ApplicationEvent 的事件 */@Datapublic class HelloEvent extends ApplicationEvent {  private String eventName;  public HelloEvent(String eventName) {    super(eventName);    setEventName(eventName);  }}/** * 自定義事件 */@Data@NoArgsConstructor@AllArgsConstructorpublic class CustomerEvent {  private String name;  private Boolean isCustomer;}/** * 監(jiān)聽器類,spring也支持一個(gè)類中監(jiān)聽多個(gè)事件 */@Component("springListener")public class SpringListener {  /**   * 監(jiān)聽所有ApplicationEvent類型 及其子類型 的事件   */  @EventListener  public void processApplicationEvent(ApplicationEvent event) {    System.out.println("process common event, class:" + event.getClass().getSimpleName());  }  /**   * 監(jiān)聽 HelloEvent類型 事件   */  @EventListener  public void processHelloEvent(HelloEvent event) {    System.out.println("process helloEvent, name:" + event.getEventName());  }  /**   * 監(jiān)聽 CustomerEvent 類型事件,但是需要滿足condition條件,即isCustomer=true   */  @EventListener(condition = "#event.isCustomer")  public void processCustomerEvent(CustomerEvent event) {    System.out.println("process customer CustomerEvent, name:" + event.getName());  }  /**   * 監(jiān)聽 CustomerEvent 類型事件,但是需要滿足condition條件,即name="miaomiao"   */  @EventListener(condition = "#event.getName().equals('miaomiao')")  public void processMiaoMiaoEvent(CustomerEvent event) {    System.out.println("process miaomiao's CustomerEvent, name:" + event.getName());  }  /**   * 支持異步處理事件   */  @Async  @EventListener  public void processAsyncCustomerEvent(CustomerEvent event) {    System.out.println("Async process CustomerEvent, name:" + event.getName());  }}//執(zhí)行類,測試入口@SpringBootApplication@ComponentScan(basePackages = {"com.example.manyao.async"})public class DemoApplication {  public static void main(String[] args) throws TException {    SpringApplication.run(DemoApplication.class, args);    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");    String[] names = context.getBeanDefinitionNames();    for(int i=0; i<names.length; i++) {      System.out.println(names[i]);    }    System.out.println("++++++++++");    context.publishEvent(new HelloEvent("helloEvent"));    context.publishEvent(new CustomerEvent("customer", true));    context.publishEvent(new CustomerEvent("miaomiao", false));  }}

結(jié)果是

//以下是spring上下文event,繼承自 ApplicationContextEvent。 用于用戶參與上下文生命周期的入口。因?yàn)槭茿pplicationEvent子類型,所以,由processApplicationEvent處理。process common event, class:ContextRefreshedEventprocess common event, class:EmbeddedServletContainerInitializedEventprocess common event, class:ApplicationReadyEventprocess common event, class:ContextRefreshedEvent//以下是上下文中的beanspringListenerorg.springframework.context.annotation.internalConfigurationAnnotationProcessororg.springframework.context.annotation.internalAutowiredAnnotationProcessororg.springframework.context.annotation.internalRequiredAnnotationProcessororg.springframework.context.annotation.internalCommonAnnotationProcessororg.springframework.context.event.internalEventListenerProcessororg.springframework.context.event.internalEventListenerFactory++++++++++//HelloEvent 繼承 ApplicationEvent,會被processApplicationEvent處理process common event, class:HelloEvent//監(jiān)聽 HelloEvent類型 的 processHelloEvent 處理process helloEvent, name:helloEvent//非 ApplicationEvent 的事件,則為 PayloadApplicationEventprocess common event, class:PayloadApplicationEvent//isCustomer=true,符合processCustomerEvent處理?xiàng)l件process customer CustomerEvent, name:customer//監(jiān)聽CustomerEvent類型,處理結(jié)果Async process CustomerEvent, name:customerprocess common event, class:PayloadApplicationEvent//符合processMiaoMiaoEvent條件process miaomiao's CustomerEvent, name:miaomiaoAsync process CustomerEvent, name:miaomiao//spring 上下文事件process common event, class:ContextClosedEvent

spring 上下文事件

上述例子中的

ContextRefreshedEvent,EmbeddedServletContainerInitializedEvent,ApplicationReadyEvent,ContextRefreshedEvent,ContextClosedEvent 等事件,都是spring上下文事件??梢酝ㄟ^監(jiān)聽這些事件,參與到spring生命周期中去。這種無侵入性交互方式,在做平臺服務(wù)時(shí),是一種很好的方式。

注冊監(jiān)聽器

org.springframework.context.event.EventListenerMethodProcessor#processBean 將所有注解EventListener的方法,存入上下文的applicationListeners中。Listener的封裝類為ApplicationListenerMethodAdapter(String beanName, Class<?> targetClass, Method method)。

org.springframework.context.support.AbstractApplicationContext#refresh 中調(diào)用 initApplicationEventMulticaster 初始化事件發(fā)布管理器applicationEventMulticaster,然后調(diào)用registerListeners() 注冊監(jiān)聽器。

發(fā)布事件

spring 起初只支持 ApplicationEvent類型事件,后來優(yōu)化之后,支持自定義事件。自定義事件的處理,默認(rèn)為PayloadApplicationEvent,相當(dāng)于EventBus的DeadEvent。

//org.springframework.context.support.AbstractApplicationContext#publishEvent(java.lang.Object, org.springframework.core.ResolvableType)  protected void publishEvent(Object event, ResolvableType eventType) {    Assert.notNull(event, "Event must not be null");    if (logger.isTraceEnabled()) {      logger.trace("Publishing event in " + getDisplayName() + ": " + event);    }    // Decorate event as an ApplicationEvent if necessary    ApplicationEvent applicationEvent;    if (event instanceof ApplicationEvent) {      applicationEvent = (ApplicationEvent) event;    }    else {    //若不是ApplicationEvent類型,則使用PayloadApplicationEvent封裝      applicationEvent = new PayloadApplicationEvent<Object>(this, event);      if (eventType == null) {        eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();      }    }    // Multicast right now if possible - or lazily once the multicaster is initialized    if (this.earlyApplicationEvents != null) {      this.earlyApplicationEvents.add(applicationEvent);    }    else {//核心操作,初始化 event      getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);    }    //調(diào)用父類,發(fā)布事件    // Publish event via parent context as well...    if (this.parent != null) {      if (this.parent instanceof AbstractApplicationContext) {        ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);      }      else {        this.parent.publishEvent(event);      }    }  }

執(zhí)行事件

@Override  public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));    //獲取事件的監(jiān)聽器集合,并逐個(gè)觸發(fā)執(zhí)行監(jiān)聽器    for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {    //異步的話,就放在線程池中執(zhí)行      Executor executor = getTaskExecutor();      if (executor != null) {        executor.execute(new Runnable() {          @Override          public void run() {            invokeListener(listener, event);          }        });      }      else {      //本線程調(diào)用        invokeListener(listener, event);      }    }  }

可以看到,spring的事件機(jī)制更復(fù)雜,但是功能同樣強(qiáng)大。

適用場景:

  1. 按照類區(qū)分事件  訂閱 事件簇  支持自定義event  按照condition過濾同類型事件

看完上述內(nèi)容,你們掌握EventBus與SpringEvent的區(qū)別是什么的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI