EventBus VS Spring Event

本文内容纲要:

- EventBus VS Spring Event

- Guava EventBus

- spring event

- 比较EventBus与Spring Event

EventBus VS Spring Event

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

Guava EventBus

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

不止是代码

/**

* Desc: 事件对象

*/

@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: 事件监听器,可以监听多个事件。处理方法添加 @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:hello

process common event, class:HelloEvent

//WorldEvent被四个监听器处理(两个自己的,两个父类的)

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把类当做事件,是以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<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 {

//找到所有事件订阅者(事件监听器)

Set<EventSubscriber> 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:HelloEvent

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

适用场景:

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

spring event

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

不止是代码

/**

* 继承 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;

}

/**

* 监听器类,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<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));

}

}

结果是

//以下是spring上下文event,继承自 ApplicationContextEvent。 用于用户参与上下文生命周期的入口。因为是ApplicationEvent子类型,所以,由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,会被processApplicationEvent处理

process common event, class:HelloEvent

//监听 HelloEvent类型 的 processHelloEvent 处理

process helloEvent, name:helloEvent

//非 ApplicationEvent 的事件,则为 PayloadApplicationEvent

process common event, class:PayloadApplicationEvent

//isCustomer=true,符合processCustomerEvent处理条件

process customer CustomerEvent, name:customer

//监听CustomerEvent类型,处理结果

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上下文事件。可以通过监听这些事件,参与到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<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);

}

//调用父类,发布事件

// 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的事件机制更复杂,但是功能同样强大。

适用场景:

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

比较EventBus与Spring Event

  • 使用方式比较

项目事件发布者发布方法是否异步监听者注册方式
EventBus任意对象EventBusEventBus#post注解Subscribe方法手动注册EventBus#register
Spring Event任意对象ApplicationEventPublisherApplicationEventPublisher#publishEvent支持同步异步注解EventListener方法系统注册

  • 使用场景比较

项目事件区分是否支持事件簇是否支持自定义event是否支持过滤是否支持事件隔离复杂程度
EventBusClass简单
Spring EventClass复杂

本文内容总结:EventBus VS Spring Event,Guava EventBus,spring event,比较EventBus与Spring Event,

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

以上是 EventBus VS Spring Event 的全部内容, 来源链接: utcz.com/z/296594.html

回到顶部