本地異步處理,采用事件機(jī)制 可以使 代碼解耦,更易讀。事件機(jī)制實(shí)現(xiàn)模式是 觀(guān)察者模式(或發(fā)布訂閱模式),主要分為三部分:發(fā)布者、監(jiān)聽(tīng)者、事件。
創(chuàng)新互聯(lián)公司專(zhuān)注于企業(yè)成都全網(wǎng)營(yíng)銷(xiāo)推廣、網(wǎng)站重做改版、浦東網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、H5場(chǎng)景定制、商城網(wǎng)站制作、集團(tuán)公司官網(wǎng)建設(shè)、成都外貿(mào)網(wǎng)站建設(shè)公司、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁(yè)設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性?xún)r(jià)比高,為浦東等各大城市提供網(wǎng)站開(kāi)發(fā)制作服務(wù)。
Guava EventBus實(shí)現(xiàn)是觀(guā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)景:
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)型事件,但是需要滿(mǎn)足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)型事件,但是需要滿(mǎn)足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)) { //異步的話(huà),就放在線(xiàn)程池中執(zhí)行 Executor executor = getTaskExecutor(); if (executor != null) { executor.execute(new Runnable() { @Override public void run() { invokeListener(listener, event); } }); } else { //本線(xiàn)程調(diào)用 invokeListener(listener, event); } } }
可以看到,spring的事件機(jī)制更復(fù)雜,但是功能同樣強(qiáng)大。
適用場(chǎng)景:
使用方式比較
項(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)鏈接
本文名稱(chēng):EventBus與SpringEvent區(qū)別詳解(EventBus事件機(jī)制,SpringEvent事件機(jī)制)
本文路徑:http://muchs.cn/article36/gphisg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供全網(wǎng)營(yíng)銷(xiāo)推廣、網(wǎng)站設(shè)計(jì)、動(dòng)態(tài)網(wǎng)站、網(wǎng)站改版、Google、定制網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)