javascript
Spring事件的观察者模式
觀察者模式的本質(zhì)是“定義對(duì)象之間的一對(duì)多依賴關(guān)系,以便當(dāng)一個(gè)對(duì)象改變狀態(tài)時(shí),其所有依賴關(guān)系都會(huì)得到通知并自動(dòng)更新。” GoF。 觀察者模式是發(fā)布/訂閱模式的子集,它允許許多觀察者對(duì)象查看事件。
可以在不同的情況下使用此模式,但總而言之,可以說(shuō)觀察者模式可以在對(duì)象應(yīng)該能夠?qū)⑾⑼ㄖ渌麑?duì)象并且您不希望這些對(duì)象緊密耦合時(shí)應(yīng)用。 就我而言,當(dāng)異步事件應(yīng)通知一個(gè)或多個(gè)圖形組件時(shí),我使用了這種模式。
可以使用臨時(shí)解決方案或使用java.util.Observer/Observable類來(lái)實(shí)現(xiàn)此模式。 但是我的項(xiàng)目總是用Spring開(kāi)發(fā)的,無(wú)論是Web還是桌面應(yīng)用 。 因此,在當(dāng)前文章中,我將解釋如何使用Spring實(shí)現(xiàn)Observer模式。
手扶
Spring ApplicationContext中的事件處理是通過(guò)ApplicationEvent類和ApplicationListener接口提供的。 如果將實(shí)現(xiàn)ApplicationListener接口的bean部署到上下文中,則每次將ApplicationEvent發(fā)布到容器時(shí), ApplicationListener都會(huì)接收到它。
Spring帶有內(nèi)置事件,例如ContextStartedEvent , ContextStoppedEvent ,但是您也可以創(chuàng)建自己的自定義事件。
為了開(kāi)發(fā)自己的事件,需要三個(gè)類, 觀察者角色, 可觀察角色和事件 。 觀察者是那些接收事件并且必須實(shí)現(xiàn)ApplicationListener類的人。 可觀察類負(fù)責(zé)發(fā)布事件,并且必須實(shí)現(xiàn)ApplicationEventPublisherAware 。 最后, 事件類必須擴(kuò)展ApplicationEvent 。
編碼
我要實(shí)現(xiàn)的是Observer模式的Wikipedia示例( http://en.wikipedia.org/wiki/Observer_pattern#Example ),但是使用Spring Events而不是Observer / Observable Java類。 該示例是一個(gè)基本的發(fā)布/訂閱示例,其中一個(gè)String消息從一個(gè)模塊發(fā)送到另一個(gè)模塊。
讓我們創(chuàng)建MessageEvent 。 此事件包含一個(gè)String,它表示我們要發(fā)送的消息。 這是一個(gè)從ApplicationEvent擴(kuò)展的簡(jiǎn)單類。
下一個(gè)類是Observable類。 此類必須實(shí)現(xiàn)ApplicationEventPublisherAware 。 此接口使用ApplicationEventPublisher作為參數(shù)定義了一個(gè)setter方法。 此參數(shù)用于發(fā)布事件。
在當(dāng)前的實(shí)現(xiàn)中,該代碼還實(shí)現(xiàn)了Runnable接口,因此用戶可以從控制臺(tái)輸入中進(jìn)行創(chuàng)建,
Observer類甚至更簡(jiǎn)單。 實(shí)現(xiàn)ApplicationListener接口。 發(fā)布事件時(shí)將調(diào)用onApplicationEvent方法。 看到它是一個(gè)通用接口,因此不需要強(qiáng)制轉(zhuǎn)換。 這不同于java.util.Observer類。
public class ResponseHandler implements ApplicationListener<MessageEvent> {public void onApplicationEvent(MessageEvent messageEvent) {System.out.println(Thread.currentThread().getName());System.out.println(messageEvent);}}在應(yīng)用程序上下文文件中,您同時(shí)注冊(cè)了ApplicationListener和ApplicationEventPublisherAware Bean。
最后是一個(gè)主類來(lái)測(cè)試系統(tǒng)。 創(chuàng)建一個(gè)線程以執(zhí)行多個(gè)異步事件。
public class MyApp {public static void main(String args[]) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext('classpath:META-INFspringapp-context.xml');EventSource eventSource = applicationContext.getBean('eventSource', EventSource.class);Thread thread = new Thread(eventSource);thread.start();}} 因此,啟動(dòng)程序并編寫(xiě)一些內(nèi)容以進(jìn)行控制臺(tái)。 您將看到類似以下內(nèi)容:
你好 Thread-0 Thread-0 MessageEvent [message = hello]
我輸入了“ hello ”消息,并打印了事件發(fā)布者的線程名 。 然后發(fā)送事件并打印處理程序線程名稱 。 最后顯示接收到的事件。 有一件事情應(yīng)該引起您的注意。 發(fā)送者( Observable )和接收者( Observer )都在同一線程中執(zhí)行; 默認(rèn)情況下,事件偵聽(tīng)器同步接收事件。 這意味著publishEvent()方法將阻塞,直到所有偵聽(tīng)器都已完成對(duì)事件的處理為止。 這種方法有很多優(yōu)點(diǎn)(例如,重用事務(wù)上下文等),但是在某些情況下,您希望每個(gè)事件都在新線程中執(zhí)行, Spring也支持此策略。
在Spring中 ,負(fù)責(zé)事件管理的類是SimpleApplicationEventMulticaster 。 此類將所有事件多播到所有注冊(cè)的偵聽(tīng)器,讓偵聽(tīng)器忽略它們不感興趣的事件。默認(rèn)行為是在調(diào)用線程中調(diào)用所有偵聽(tīng)器。
現(xiàn)在,我將解釋如何初始化Spring Event Architecture以及如何進(jìn)行修改。 默認(rèn)情況下,當(dāng)ApplicationContext為 啟動(dòng)后,它將調(diào)用initApplicationEventMulticaster方法。 此方法驗(yàn)證是否存在與類型ApplicationEventMulticaster的ID applicationEventMulticaster的bean。 如果是這樣,則使用已定義的ApplicationEventMulticaster ,否則,將創(chuàng)建具有默認(rèn)配置的新SimpleApplicationEventMulticaster 。
SimpleApplicationEventMulticaster具有可用于指定哪些java.util.concurrent.Executor將執(zhí)行事件setTaskExecutor。 因此,如果您希望每個(gè)事件在不同的線程中執(zhí)行,那么一個(gè)好的方法是使用ThreadPoolExecutor 。 如上一段所述,現(xiàn)在我們必須顯式定義SimpleApplicationEventMulticaster而不是 使用默認(rèn)的。 讓我們實(shí)現(xiàn):
<beans xmlns='http:www.springframework.orgschemabeans' xmlns:xsi='http:www.w3.org2001XMLSchema-instance' xmlns:context='http:www.springframework.orgschemacontext' xmlns:task='http:www.springframework.orgschematask' xsi:schemaLocation='http:www.springframework.orgschematask http:www.springframework.orgschemataskspring-task-3.0.xsd http:www.springframework.orgschemabeans http:www.springframework.orgschemabeansspring-beans-3.0.xsd http:www.springframework.orgschemacontext http:www.springframework.orgschemacontextspring-context-3.0.xsd'><bean id='eventSource' class='org.asotobu.oo.EventSource' > <bean id='responseHandler' class='org.asotobu.oo.ResponseHandler' > <task:executor id='pool' pool-size='10' > <bean id='applicationEventMulticaster' class='org.springframework.context.event.SimpleApplicationEventMulticaster'><property name='taskExecutor' ref='pool' > <bean><beans> 首先,必須將SimpleApplicationEventMulticaster定義為ID為applicationEventMulticaster的bean。 然后設(shè)置任務(wù)池,然后我們重新運(yùn)行主類。 輸出將是:
你好 線程1 池1 MessageEvent [message = hello]
請(qǐng)注意,現(xiàn)在發(fā)送方和接收方線程有所不同。
當(dāng)然,您可以為更復(fù)雜的操作創(chuàng)建自己的ApplicationEventMulticaster 。 您只需要實(shí)現(xiàn)ApplicationEventMulticaster并使用applicationEventMulticaster bean名稱定義它,事件將根據(jù)您自己的策略執(zhí)行。
希望現(xiàn)在您的Spring桌面應(yīng)用程序可以充分利用Spring事件來(lái)分隔模塊。
下載代碼。
參考:來(lái)自JCG合作伙伴 Alex Soto的Spring Events觀察者模式,來(lái)自O(shè)ne Jar To Rule All All博客。
翻譯自: https://www.javacodegeeks.com/2012/08/observer-pattern-with-spring-events.html
總結(jié)
以上是生活随笔為你收集整理的Spring事件的观察者模式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 荣耀 CEO 赵明:替华为的老同事高兴,
- 下一篇: Spring测试支持和上下文缓存