EventBus与SpringEvent的区别是什么
创始人
2024-12-25 01:28:49
0次
Guava EventBus

Guava EventBus实现是观察者模式,用法很简单,先上代码。

/** * 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: 事件监听器,可以监听多个事件。处理方法添加 @Subscribe 注解即可。 */public class GeventListener {   /**   * 监听 HelloEvent 类型及其父类型(Object)的事件   */  @Subscribe  public void processEvent(HelloEvent event){    System.out.println("process hello event, name:" + event.getEventName());  }   /**   * 监听 WorldEvent 类型及其父类型(HelloEvent 和 Object)的事件   */  @Subscribe  public void processWorldEvent(WorldEvent event) {    System.out.println("process world eventV1, no:" + event.getEventNo() + ", name:" + event.getEventName());  }  /**   * 注册多个监听器 监听同一事件   * @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));  }}

结果如下:

//HelloEvent被两个监听器处理(HelloEvent类及Object类的监听器)process hello event, name:helloprocess common event, class:HelloEvent//WorldEvent被四个监听器处理(两个自己的,两个父类的)process world eventV1, no:23333, name:worldprocess world eventV2, no:23333, name:worldprocess hello event, name:worldprocess common event, class:WorldEvent

由上可知:Guava EventBus把类当做事件,是以class为key注册和管理事件的,value是事件监听器的method;事件监听器只处理某一类(及其父类)事件。

事件注册与发布

//com.google.common.eventbus.EventBus#register public void register(Object object) { //key为Class, value为EventSubscriber(Object target, Method method)【集合】。注意这里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 public void post(Object event) {   //找到event类及其所有父类  Set> dispatchTypes = flattenHierarchy(event.getClass());  boolean dispatched = false;  for (Class eventType : dispatchTypes) {   subscribersByTypeLock.readLock().lock();   try {   //找到所有事件订阅者(事件监听器)    Set wrappers = subscribersByType.get(eventType);    if (!wrappers.isEmpty()) {     dispatched = true;     for (EventSubscriber wrapper : wrappers) {     //事件入队列      enqueueEvent(event, wrapper);     }    }   } finally {    subscribersByTypeLock.readLock().unlock();   }  }//如果没有订阅者订阅此类消息,则为 DeadEvent  if (!dispatched && !(event instanceof DeadEvent)) {   post(new DeadEvent(this, event));  }  dispatchQueuedEvents(); }

事件隔离

多个EventBus可以隔离事件。

public class AnotherListener {  /**   * 监听 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));  }}

结果是

//eventBus结果与之前相同process hello event, name:hello//anotherEventBus 发布的事件,只被其注册的监听器处理process common event, class:HelloEventprocess another world event, no:666, name:AnotherWorld

适用场景:

  1. 按照类区分事件  订阅 事件簇  支持自定义event,可以根据event自己写分发器  事件隔离

spring event

spring 新版事件机制也比较简单,看代码。

/** * 继承 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;}/** * 监听器类,spring也支持一个类中监听多个事件 */@Component("springListener")public class SpringListener {  /**   * 监听所有ApplicationEvent类型 及其子类型 的事件   */  @EventListener  public void processApplicationEvent(ApplicationEvent event) {    System.out.println("process common event, class:" + event.getClass().getSimpleName());  }  /**   * 监听 HelloEvent类型 事件   */  @EventListener  public void processHelloEvent(HelloEvent event) {    System.out.println("process helloEvent, name:" + event.getEventName());  }  /**   * 监听 CustomerEvent 类型事件,但是需要满足condition条件,即isCustomer=true   */  @EventListener(condition = "#event.isCustomer")  public void processCustomerEvent(CustomerEvent event) {    System.out.println("process customer CustomerEvent, name:" + event.getName());  }  /**   * 监听 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());  }}//执行类,测试入口@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

结果是

//以下是spring上下文event,继承自 ApplicationContextEvent。 用于用户参与上下文生命周期的入口。因为是ApplicationEvent子类型,所以,由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//监听 HelloEvent类型 的 processHelloEvent 处理process helloEvent, name:helloEvent//非 ApplicationEvent 的事件,则为 PayloadApplicationEventprocess common event, class:PayloadApplicationEvent//isCustomer=true,符合processCustomerEvent处理条件process customer CustomerEvent, name:customer//监听CustomerEvent类型,处理结果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上下文事件。可以通过监听这些事件,参与到spring生命周期中去。这种无侵入性交互方式,在做平台服务时,是一种很好的方式。

注册监听器

org.springframework.context.event.EventListenerMethodProcessor#processBean 将所有注解EventListener的方法,存入上下文的applicationListeners中。Listener的封装类为ApplicationListenerMethodAdapter(String beanName, Class targetClass, Method method)。

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)  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(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);    }    //调用父类,发布事件    // 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);      }    }  }

执行事件

@Override  public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));    //获取事件的监听器集合,并逐个触发执行监听器    for (final ApplicationListener listener : getApplicationListeners(event, type)) {    //异步的话,就放在线程池中执行      Executor executor = getTaskExecutor();      if (executor != null) {        executor.execute(new Runnable() {          @Override          public void run() {            invokeListener(listener, event);          }        });      }      else {      //本线程调用        invokeListener(listener, event);      }    }  }

可以看到,spring的事件机制更复杂,但是功能同样强大。

适用场景:

  1. 按照类区分事件  订阅 事件簇  支持自定义event  按照condition过滤同类型事件

相关内容

热门资讯

空调连续工作多久需要停机休息 空调连续工作的时间取决于多个因素,包括空调的型号、功率、使用环境和维护情况等。一般来说,空调可以连续...
空调哪个符号是除湿的 空调除湿功能通常用一个水滴形状的符号表示。不同品牌和型号的空调遥控器可能会有所差异,但一般来说,除湿...
格力空调多长时间加一次氟利昂 1、一般情况下,空调对氟利昂的使用量是非常小的,所以在空调使用了四年左右的时候再考虑加也没问题。2、...
空调用多长时间需要加氟一次 一般情况下是五年。当出现以下这几种情况时,空调才需要加氟。1、空调的室内机和室外机各有两个接口,当接...
格调生活·C标思享荟:卡萨帝在... 9月12日的郑州龙湖金融岛,夜风轻拂,灯光璀璨。“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑...
品牌价值破千亿、高端份额持续领... 9月12日,“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑州站”在郑州龙湖金融岛举办。2026...
空调主板坏了修800还是换新的 空调主板坏了是修还是换新,需要考虑多个因素,以下是一些建议:1. 维修成本:如果维修费用较低,比如 ...
空调开多久需要休息多长时间 问题:空调开多久需要休息多长时间回答:1、在使用空调的过程中,一般空调开7~8个小时左右需要休息2~...
中央空调多长时间清洗一次 1、一般空调开机前清洗一次即可,空调开机中间时段再清洗一次,空调关机时清洗一次,这样比较合理。2、空...
中央空调氟利昂多久加一次 看空调制热和制冷程度,很多人的观点认为氟利昂必须一年放一次,其实这个观点是错误的,理解上面有点偏差,...