最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

EventBus與Spring Event區(qū)別詳解(EventBus 事件機(jī)制,Spring Event事件機(jī)制)

 更新時(shí)間:2020年02月07日 14:25:22   作者:漫夭  
這篇文章主要介紹了EventBus與Spring Event區(qū)別,需要的朋友可以參考下

本地異步處理,采用事件機(jī)制 可以使 代碼解耦,更易讀。事件機(jī)制實(shí)現(xiàn)模式是 觀察者模式(或發(fā)布訂閱模式),主要分為三部分:發(fā)布者、監(jiān)聽(tīng)者、事件。

Guava EventBus

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

/**
 * Desc: 事件對(duì)象
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class HelloEvent {
  private String eventName;
}
 
 
@Data
@NoArgsConstructor
public class WorldEvent extends HelloEvent {
 
  private int eventNo;
 
  public WorldEvent(String name, int no) {
    setEventName(name);
    setEventNo(no);
  }
}
 
/**
 * Desc: 事件監(jiān)聽(tīng)器,可以監(jiān)聽(tīng)多個(gè)事件。處理方法添加 @Subscribe 注解即可。
 */
public class GeventListener {
 
  /**
   * 監(jiān)聽(tīng) HelloEvent 類(lèi)型及其父類(lèi)型(Object)的事件
   */
  @Subscribe
  public void processEvent(HelloEvent event){
    System.out.println("process hello event, name:" + event.getEventName());
  }
 
  /**
   * 監(jiān)聽(tīng) WorldEvent 類(lèi)型及其父類(lèi)型(HelloEvent 和 Object)的事件
   */
  @Subscribe
  public void processWorldEvent(WorldEvent event) {
    System.out.println("process world eventV1, no:" + event.getEventNo() + ", name:" + event.getEventName());
  }
  /**
   * 注冊(cè)多個(gè)監(jiān)聽(tīng)器 監(jiān)聽(tīng)同一事件
   * @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)聽(tīng)器處理(HelloEvent類(lèi)及Object類(lèi)的監(jiān)聽(tīng)器)
process hello event, name:hello
process common event, class:HelloEvent
//WorldEvent被四個(gè)監(jiān)聽(tīng)器處理(兩個(gè)自己的,兩個(gè)父類(lèi)的)
process world eventV1, no:23333, name:world
process world eventV2, no:23333, name:world
process hello event, name:world
process common event, class:WorldEvent

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

事件注冊(cè)與發(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類(lèi)及其所有父類(lèi)
  Set<Class<?>> dispatchTypes = flattenHierarchy(event.getClass());
  boolean dispatched = false;
  for (Class<?> eventType : dispatchTypes) {
   subscribersByTypeLock.readLock().lock();
   try {
   //找到所有事件訂閱者(事件監(jiān)聽(tīng)器)
    Set<EventSubscriber> wrappers = subscribersByType.get(eventType);
    if (!wrappers.isEmpty()) {
     dispatched = true;
     for (EventSubscriber wrapper : wrappers) {
     //事件入隊(duì)列
      enqueueEvent(event, wrapper);
     }
    }
   } finally {
    subscribersByTypeLock.readLock().unlock();
   }
  }
//如果沒(méi)有訂閱者訂閱此類(lèi)消息,則為 DeadEvent
  if (!dispatched && !(event instanceof DeadEvent)) {
   post(new DeadEvent(this, event));
  }
  dispatchQueuedEvents();
 }

事件隔離

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

public class AnotherListener {
  /**
   * 監(jiān)聽(tīng) WorldEvent 類(lèi)型及其父類(lèi)型(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ā)布的事件,只被其注冊(cè)的監(jiān)聽(tīng)器處理

process common event, class:HelloEvent

process another world event, no:666, name:AnotherWorld

適用場(chǎng)景:

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

spring event

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

/**
 * 繼承 ApplicationEvent 的事件
 */
@Data
public class HelloEvent extends ApplicationEvent {
  private String eventName;
  public HelloEvent(String eventName) {
    super(eventName);
    setEventName(eventName);
  }
}
/**
 * 自定義事件
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CustomerEvent {
  private String name;
  private Boolean isCustomer;
}
/**
 * 監(jiān)聽(tīng)器類(lèi),spring也支持一個(gè)類(lèi)中監(jiān)聽(tīng)多個(gè)事件
 */
@Component("springListener")
public class SpringListener {
  /**
   * 監(jiān)聽(tīng)所有ApplicationEvent類(lèi)型 及其子類(lèi)型 的事件
   */
  @EventListener
  public void processApplicationEvent(ApplicationEvent event) {
    System.out.println("process common event, class:" + event.getClass().getSimpleName());
  }
  /**
   * 監(jiān)聽(tīng) HelloEvent類(lèi)型 事件
   */
  @EventListener
  public void processHelloEvent(HelloEvent event) {
    System.out.println("process helloEvent, name:" + event.getEventName());
  }
  /**
   * 監(jiān)聽(tīng) CustomerEvent 類(lèi)型事件,但是需要滿足condition條件,即isCustomer=true
   */
  @EventListener(condition = "#event.isCustomer")
  public void processCustomerEvent(CustomerEvent event) {
    System.out.println("process customer CustomerEvent, name:" + event.getName());
  }
  /**
   * 監(jiān)聽(tīng) CustomerEvent 類(lèi)型事件,但是需要滿足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í)行類(lèi),測(cè)試入口
@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。 用于用戶(hù)參與上下文生命周期的入口。因?yàn)槭茿pplicationEvent子類(lèi)型,所以,由processApplicationEvent處理。
process common event, class:ContextRefreshedEvent
process common event, class:EmbeddedServletContainerInitializedEvent
process common event, class:ApplicationReadyEvent
process common event, 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,會(huì)被processApplicationEvent處理
process common event, class:HelloEvent
//監(jiān)聽(tīng) HelloEvent類(lèi)型 的 processHelloEvent 處理
process helloEvent, name:helloEvent
//非 ApplicationEvent 的事件,則為 PayloadApplicationEvent
process common event, class:PayloadApplicationEvent
//isCustomer=true,符合processCustomerEvent處理?xiàng)l件
process customer CustomerEvent, name:customer
//監(jiān)聽(tīng)CustomerEvent類(lèi)型,處理結(jié)果
Async process CustomerEvent, name:customer
process common event, class:PayloadApplicationEvent
//符合processMiaoMiaoEvent條件
process miaomiao's CustomerEvent, name:miaomiao
Async process CustomerEvent, name:miaomiao
//spring 上下文事件
process common event, class:ContextClosedEvent

spring 上下文事件

上述例子中的

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

注冊(cè)監(jiān)聽(tīng)器

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

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

發(fā)布事件

spring 起初只支持 ApplicationEvent類(lèi)型事件,后來(lái)優(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類(lèi)型,則使用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)用父類(lèi),發(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)聽(tīng)器集合,并逐個(gè)觸發(fā)執(zhí)行監(jiān)聽(tīng)器
    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)大。

適用場(chǎng)景:

  1. 按照類(lèi)區(qū)分事件
  2. 訂閱 事件簇
  3. 支持自定義event
  4. 按照condition過(guò)濾同類(lèi)型事件

比較EventBus與Spring Event

使用方式比較

項(xiàng)目 事件 發(fā)布者 發(fā)布方法 是否異步 監(jiān)聽(tīng)者 注冊(cè)方式
EventBus 任意對(duì)象 EventBus EventBus#post 注解Subscribe方法 手動(dòng)注冊(cè)EventBus#register
Spring Event 任意對(duì)象 ApplicationEventPublisher ApplicationEventPublisher#publishEvent 支持同步異步 注解EventListener方法 系統(tǒng)注冊(cè)

使用場(chǎng)景比較

項(xiàng)目 事件區(qū)分 是否支持事件簇 是否支持自定義event 是否支持過(guò)濾 是否支持事件隔離 復(fù)雜程度
EventBus Class 簡(jiǎn)單
Spring Event Class 復(fù)雜

更多關(guān)于EventBus與Spring Event文章大家可查看下面的相關(guān)鏈接

相關(guān)文章

  • org.slf4j.Logger中info()方法的使用詳解

    org.slf4j.Logger中info()方法的使用詳解

    這篇文章主要介紹了org.slf4j.Logger中info()方法的使用詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Java?Handler同步屏障淺析講解

    Java?Handler同步屏障淺析講解

    同步屏障機(jī)制是什么?Handler發(fā)送的消息分為普通消息、屏障消息、異步消息,一旦Looper在處理消息時(shí)遇到屏障消息,那么就不再處理普通的消息,而僅僅處理異步的消息。不再使用屏障后,需要撤銷(xiāo)屏障,不然就再也執(zhí)行不到普通消息了
    2022-08-08
  • Java過(guò)濾XSS腳本攻擊詳細(xì)代碼示例

    Java過(guò)濾XSS腳本攻擊詳細(xì)代碼示例

    這篇文章主要介紹了Java過(guò)濾XSS腳本攻擊的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • Java中Properties配置類(lèi)用法詳解

    Java中Properties配置類(lèi)用法詳解

    所謂的配置文件問(wèn)題,是指我們?cè)陂_(kāi)發(fā)時(shí),經(jīng)常需要讀取和修改一些配置信息,比如數(shù)據(jù)庫(kù)、消息隊(duì)列、Nginx、Web服務(wù)器等的配置,為了便于修改這些信息,我們可以采用Properties配置類(lèi),本文給大家講一下Properties配置類(lèi)是怎么回事,以及怎么使用
    2023-06-06
  • Mybatis在sqlite中無(wú)法讀寫(xiě)byte[]類(lèi)問(wèn)題的解決辦法

    Mybatis在sqlite中無(wú)法讀寫(xiě)byte[]類(lèi)問(wèn)題的解決辦法

    這篇文章主要給大家介紹了關(guān)于Mybatis在sqlite中無(wú)法讀寫(xiě)byte[]類(lèi)問(wèn)題的解決辦法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • 使用Java實(shí)現(xiàn)DNS域名解析的簡(jiǎn)單示例

    使用Java實(shí)現(xiàn)DNS域名解析的簡(jiǎn)單示例

    這篇文章主要介紹了使用Java實(shí)現(xiàn)DNS域名解析的簡(jiǎn)單示例,包括對(duì)一個(gè)動(dòng)態(tài)IP主機(jī)的域名解析例子,需要的朋友可以參考下
    2015-10-10
  • Java?C++題解leetcode817鏈表組件示例

    Java?C++題解leetcode817鏈表組件示例

    這篇文章主要為大家介紹了Java?C++題解leetcode817鏈表組件示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • java網(wǎng)上圖書(shū)商城(1)User模塊

    java網(wǎng)上圖書(shū)商城(1)User模塊

    這篇文章主要介紹了java網(wǎng)上圖書(shū)商城,User模塊,實(shí)現(xiàn)用戶(hù)注冊(cè)功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • 在spring中實(shí)例化bean無(wú)效的問(wèn)題

    在spring中實(shí)例化bean無(wú)效的問(wèn)題

    這篇文章主要介紹了在spring中實(shí)例化bean無(wú)效的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • SpringBoot集成EasyExcel的步驟

    SpringBoot集成EasyExcel的步驟

    EasyExcel是阿里巴巴開(kāi)源poi插件之一,主要解決了poi框架使用復(fù)雜,sax解析模式不容易操作,數(shù)據(jù)量大起來(lái)容易OOM,解決了POI并發(fā)造成的報(bào)錯(cuò)。主要解決方式:通過(guò)解壓文件的方式加載,一行一行的加載,并且拋棄樣式字體等不重要的數(shù)據(jù),降低內(nèi)存的占用。
    2021-06-06

最新評(píng)論

左权县| 临夏县| 江津市| 石嘴山市| 阿巴嘎旗| 金华市| 勐海县| 彰武县| 灵宝市| 延津县| 黑河市| 渝北区| 克东县| 晋中市| 达尔| 喀什市| 普陀区| 永丰县| 清流县| 潜山县| 大名县| 墨玉县| 麻城市| 绥化市| 康保县| 肥乡县| 安化县| 牡丹江市| 祁门县| 呼和浩特市| 杭锦后旗| 巧家县| 涞源县| 榕江县| 高邑县| 茌平县| 闸北区| 山东省| 南宫市| 青阳县| 徐闻县|