JSF基于事件的交流:新派方法

在上一篇文章中 ,我們學習了基于Observer / Event Listener和Mediator模式的基于事件的通信。 由于它們的缺點,我想展示基于事件的通信的更有效方法。 我們將從Google Guava EventBus開始,以CDI (Java EE平臺的上下文和依賴注入)結束。

番石榴EventBus

Google Guava庫具有有用的package eventbus 。 EventBus類允許組件之間進行發布-訂閱式通信,而無需組件之間進行顯式注冊。 因為我們開發Web應用程序,所以我們應該將此類的實例封裝在有作用域的bean中。

讓我們編寫EventBusProvider bean。

public class EventBusProvider implements Serializable {private EventBus eventBus = new EventBus("scopedEventBus");public static EventBus getEventBus() {// access EventBusProvider beanELContext elContext = FacesContext.getCurrentInstance().getELContext();EventBusProvider eventBusProvider =(EventBusProvider) elContext.getELResolver().getValue(elContext, null, "eventBusProvider");return eventBusProvider.eventBus;}
}

我僅以一個示例來演示Guava EventBus的所有主要功能。 讓我們編寫以下事件層次結構:

public class SettingsChangeEvent {}public class LocaleChangeEvent extends SettingsChangeEvent {public LocaleChangeEvent(Object newLocale) {...}
}public class TimeZoneChangeEvent extends SettingsChangeEvent {public TimeZoneChangeEvent(Object newTimeZone) {...}
}
下一步很簡單。 要接收事件,對象(bean)應公開一個公共方法,該方法以@Subscribe批注進行批注,該方法接受具有所需事件類型的單個參數。 該對象需要將自身傳遞給EventBus實例的register()方法。 讓我們創建兩個bean:
public MyBean1 implements Serializable {@PostConstructpublic void initialize() throws Exception {EventBusProvider.getEventBus().register(this);}@Subscribepublic void handleLocaleChange(LocaleChangeEvent event) {// do something}@Subscribepublic void handleTimeZoneChange(TimeZoneChangeEvent event) {// do something}
}public MyBean2 implements Serializable {@PostConstructpublic void initialize() throws Exception {EventBusProvider.getEventBus().register(this);}@Subscribepublic void handleSettingsChange(SettingsChangeEvent event) {// do something}
}

要發布事件,只需將事件對象提供給EventBus實例的post()方法。 EventBus實例將確定事件的類型并將其路由到所有已注冊的偵聽器。

public class UserSettingsForm implements Serializable {private boolean changed;public void localeChangeListener(ValueChangeEvent e) {changed = true;        // notify subscribersEventBusProvider.getEventBus().post(new LocaleChangeEvent(e.getNewValue()));}public void timeZoneChangeListener(ValueChangeEvent e) {changed = true;        // notify subscribersEventBusProvider.getEventBus().post(new TimeZoneChangeEvent(e.getNewValue()));}public String saveUserSettings() {...if (changed) {// notify subscribersEventBusProvider.getEventBus().post(new SettingsChangeEvent());return "home";}}
}
Guava EventBus允許創建對許多不同事件做出反應的任何偵聽器,只需使用@Subscribe注釋許多方法即可。 偵聽器可以利用現有事件層次結構。 因此,如果偵聽器A正在等待事件A,并且事件A具有名為B的子類,則此偵聽器將接收兩種類型的事件:A和B。在我們的示例中,我們發布了三個事件:SettingsChangeEvent,LocaleChangeEvent和TimeZoneChangeEvent。 MyBean1中的handleLocaleChange()方法將僅接收LocaleChangeEvent。 方法handleTimeZoneChange()將僅接收TimeZoneChangeEvent。 但是,請查看MyBean2中的handleSettingsChange()方法。 它將接收所有三個事件!
如您所見,仍然需要手動注冊(EventBusProvider.getEventBus()。register(this)),并且在上一篇文章中提到的作用域bean的問題仍然存在。 我們應該注意EventBusProvider的作用域和發布/訂閱者bean的作用域。 但是,正如您可能還會看到的,與Mediator模式相比,我們有了一些改進:不需要特殊的接口,沒有固定定義訂戶的方法名,也可以進行多偵聽器,不花精力管理注冊的實例,等等。但并非最不重要的是-異步AsyncEventBus和對DeadEvent的訂閱(用于偵聽沒有偵聽器調度的任何事件-便于調試)。 請按照本指南將現有的基于EventListener的系統轉換為基于EventBus的系統。
CDI(上下文和依賴注入)
每個符合JEE 6的應用服務器都支持CDI(JSR-299規范)。 它定義了一組補充服務,可幫助改善應用程序代碼的結構。 CDI的最著名的實現是OpenWebBeans和JBoss Weld 。 CDI中的事件允許bean完全不依賴地進行交互。 事件生產者引發事件,這些事件由容器傳遞給事件觀察者。 這個基本架構聽起來像熟悉的Observer / Observable模式,但是有很多好處。
  • 事件生產者和事件觀察者彼此分離。
  • 觀察者可以指定“選擇器”的組合來縮小他們將接收的事件通知的范圍。
  • 可以立即或延遲通知觀察者,直到當前事務結束為止。
  • 使用條件觀察者方法進行作用域定義時不會感到頭痛(還記得作用域bean和Mediator / EventBus的問題嗎?)。
條件觀察者方法僅在聲明觀察者方法的bean范圍當前處于活動狀態時才允許獲取已經存在的bean實例,而無需創建新的bean實例。 如果觀察者方法不是有條件的,則將始終創建相應的bean。 您很靈活!
在我看來,CDI事件機制是進行基于事件的交流的最佳方法。 這個問題很復雜。 讓我們只顯示基本功能。 觀察者方法是帶有參數@Observes的bean的方法。
public MyBean implements Serializable {public void onLocaleChangeEvent(@Observes Locale locale) {...}
}

如果觀察者方法僅對限定的事件感興趣,則事件參數也可以指定限定符-這些事件具有限定符。

public void onLocaleChangeEvent(@Observes @Updated Locale locale) {...
}

事件限定符只是使用@Qualifier定義的普通限定符。 這是一個例子:

@Qualifier
@Target({FIELD, PARAMETER})
@Retention(RUNTIME)
public @interface Updated {}

事件生產者使用參數化Event接口的實例觸發事件。 該接口的實例通過注入獲得。 生產者通過調用Event接口的fire()方法并傳遞事件對象來引發事件。

public class UserSettingsForm implements Serializable {@Inject @Any Event<Locale> localeEvent;public void localeChangeListener(ValueChangeEvent e) {// notify all observerslocaleEvent.fire((Locale)e.getNewValue());}
}
容器調用所有觀察者方法,并將事件對象作為事件參數的值傳遞。 如果任何觀察者方法引發異常,則容器將停止調用觀察者方法,并且該異常將由fire()方法重新拋出。 上面的@Any注釋充當所有限定符的別名。 您會看到,無需手動注冊觀察員。 簡單? 在注入點指定其他限定詞也很簡單:
// this will raise events to observers having parameter @Observes @Updated Locale
@Inject @Updated Event<Locale> localeEvent;
您還可以具有多個事件限定符。 該事件將傳遞給每個具有事件參數的觀察者方法,該事件參數可以分配事件對象,并且除了與事件注入點指定的事件限定符匹配的事件限定符之外,沒有任何事件限定符。 觀察者方法可能具有其他參數,這些參數是注入點。 例:
public void onLocaleChangeEvent(@Observes @Updated Locale locale, User user) {...
}

動態指定限定符是什么? CDI允許通過AnnotationLiteral獲得適當的限定符實例。 這樣,我們可以將限定符傳遞給Event的select()方法。 例:

public class DocumentController implements Serializable {Document document;@Inject @Updated @Deleted Event<Document> documentEvent;public void updateDocument() {...// notify observers with @Updated annotationdocumentEvent.select(new AnnotationLiteral<Updated>(){}).fire(document);}public void deleteDocument() {...// notify observers with @Deleted annotationdocumentEvent.select(new AnnotationLiteral<Deleted>(){}).fire(document);}
}
讓我們談談“條件觀察者方法”。 默認情況下,如果當前上下文中沒有觀察者實例,則容器將實例化觀察者以向其傳遞事件。 這種行為并不總是令人滿意的。 我們可能只想將事件傳遞給當前上下文中已經存在的觀察者實例。 通過在@Observes批注中添加receive = IF_EXISTS來指定條件觀察者。
public void onLocaleChangeEvent(@Observes(receive = IF_EXISTS) @Updated Locale locale) {...
}
在此處閱讀有關范圍和上下文的更多信息。 在這篇簡短的文章中,我們不能再談論更多功能,例如“具有成員的事件限定符”和“事務觀察者”。 我想鼓勵大家開始學習CDI。 玩得開心!
參考: JSF中基于事件的通信。 新學派的方法 。 來自我們的JCG合作伙伴 Oleg Varaksin,來自“軟件開發思想”博客。

翻譯自: https://www.javacodegeeks.com/2012/07/jsf-event-based-communication-new.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/371887.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/371887.shtml
英文地址,請注明出處:http://en.pswp.cn/news/371887.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

菜鳥之路-淺談設計模式之單例設計模式

單例設計模式 定義&#xff1a;確保一個類僅僅有一個實例&#xff0c;并且自行實例化并向整個系統提供這個實例。單例模式是一種經常使用的軟件設計模式。在它的核心結構中僅僅包括一個被稱為單例的特殊類。通過單例模式能夠保證系統中一個類僅僅有一個實例并且該實例易于外界訪…

python 32bit數據結構_python實現bitmap數據結構詳解

bitmap是很常見的算法設計&#xff0c;例如用以Bloom Filter中&#xff1b;用以無反復整數金額的排列這些。bitmap一般根據數組來完成&#xff0c;數組中每一個原素能夠當做是一系列二進制數&#xff0c;全部元素組成更高的二進制結合。針對Python而言&#xff0c;整數金額種類…

MVC如何使用開源分頁插件shenniu.pager.js

最近比較忙&#xff0c;前期忙公司手機端接口項目&#xff0c;各種開發調試發布現在幾乎上線無問題了&#xff1b;雖然公司項目忙不過在期間抽空做了兩件個人覺得有意義的事情&#xff0c;一者使用aspnetcore開發了個人線上項目&#xff08;要說線上其實只能ip訪問&#xff0c;…

四. 基于環視Camera的BEV感知算法-PETR

目錄 前言0. 簡述1. 算法動機&開創性思路2. 主體結構3. 損失函數4. 性能對比5. PETRv2總結下載鏈接參考 前言 自動駕駛之心推出的《國內首個BVE感知全棧系列學習教程》&#xff0c;鏈接。記錄下個人學習筆記&#xff0c;僅供自己參考 本次課程我們來學習下課程第四章——基…

Java EE 6 VS Spring 3:Java EE已經殺死了Spring? 沒門!

介紹 幾天前&#xff0c;我在聽Java Spotlight Podcast的插曲85 。 在這次演講中&#xff0c; Bert Ertman和Paul Bakker討論了從Spring遷移到Java EE。 基本上&#xff0c;在他們的介紹中&#xff0c;他們說&#xff0c;如今&#xff0c;選擇Spring而不是Java EE是沒有意義的。…

usb檢測串口是哪個角_怎樣測試串口和串口線是否正常

一步&#xff1a;把串口線或者USB轉串口線插到計算機上。二步&#xff1a;打開串口調試助手接著選擇串口&#xff0c;串口線和 USB 轉串口的端口號查看路徑&#xff1a;電腦上--右鍵--屬性--硬件--設備管理器-端口(COM 和LPT),點開端口前面的號查看即可。注釋&#xff1a;1、US…

NodeJS常用模塊介紹

收集了NodeJS開發中常用的一些模塊。MVC框架 - Express Express 是輕量靈活的Nodejs Web應用框架&#xff0c;它可以快速地搭建網站。Express框架建立在Nodejs內置的Http模塊上&#xff0c;并對Http模塊再包裝&#xff0c;從而實際Web請求處理的 功能。它支持多種前端模板&…

Java泛型面試問題

Java面試中的通用面試問題在相當長的時間內在Java 5周圍越來越普遍&#xff0c;許多應用程序都轉移到Java 5上&#xff0c;并且幾乎所有新的Java開發都發生在Tiger&#xff08;Java 5的代號&#xff09;上。 泛型和Java 5功能&#xff08;例如Enum&#xff09;的重要性&#xf…

隱層元素閃一下_太陽一直依靠什么元素在燃燒,地球上的重元素又是怎么來的?...

本文基于回答網友一個這樣的問題&#xff1a;太陽目前氫核聚變是氦碳氧穩定燃燒地球上的鐵鎳重元素哪里來的&#xff1f;可以說&#xff0c;這是一個毫無邏輯亂七八糟的問題&#xff0c;但既然邀請回答&#xff0c;就從中挑出幾個稍顯合理的問題說明一下。太陽核心每時每刻都在…

基于Token的WEB后臺認證機制

基于Token的WEB后臺認證機制 幾種常用的認證機制 HTTP Basic Auth HTTP Basic Auth簡單點說明就是每次請求API時都提供用戶的username和password&#xff0c;簡言之&#xff0c;Basic Auth是配合RESTful API 使用的最簡單的認證方式&#xff0c;只需提供用戶名密碼即可&#xf…

JSF基于事件的溝通:過時的方法

用JSF編寫的Web應用程序由相互交互的bean組成。 在開發Web應用程序時&#xff0c;bean之間的通信是主要的設計模式之一。 有時&#xff0c;一個bean需要向其他bean發送事件&#xff0c;以通知它們某些更改或其他任何更改。 我們通常可以將托管bean或Spring bean注入另一個bean的…

mysql調優 基礎

MySQL調優可以從幾個方面來做&#xff1a;1. 架構層&#xff1a;做從庫&#xff0c;實現讀寫分離&#xff1b;2.系統層次&#xff1a;增加內存&#xff1b;給磁盤做raid0或者raid5以增加磁盤的讀寫速度&#xff1b;可以重新掛載磁盤&#xff0c;并加上noatime參數&#xff0c;這…

saltstack

第一&#xff1a;安裝前準備&#xff1a; 聲明我用的是ubuntu 16.04的系統 1.修改主機名&#xff0c;并保證兩臺機器可以互相ping同主機名 ip1 master_hostname ip2 slave_hostname 第二&#xff1a;安裝 服務器安裝 yum install salt-master -y客戶端安裝 yum install salt…

ios 百度地圖指定區域_獲取百度地圖可視區域范圍的數據

有個業務場景&#xff0c;需要根據獲取到的地圖區域顯示&#xff0c;根據相應的經緯度反查 左側區域的會議室。思路&#xff1a;1.得到百度地圖可視區域--可視區域的中心點2.可視區域的四個角的其中兩個(東北角西南角)http://lbsyun.baidu.com/cms/jsapi/reference/jsapi_refer…

使用WS-Trust / STS采樣器擴展JMeter

JMeter沒有對WS-Security或WS-Trust的任何內置支持&#xff0c;這使我為JMeter開發了此STS Sampler –可以在負載測試STS時使任何人的生活變得更好。 首先&#xff0c;您需要擁有Apache JMeter發行版。 我正在使用v2.7。 然后&#xff0c;您可以從此處下載sts.sampler.zip –解…

分享一個使用閉包對一個對象繼承方式

function Person(name,age){this.name name;this.age age; }//定義一個new函數 繼承了對Person的繼承 function New(obj){return function(){var o {"__proto__":obj.proto};obj.apply(o,arguments);}return obj; }var n new New(Person)("對象繼承了person…

vue怎么改logo_vue全家桶項目構建教程

前言vue是現階段很流行的前端框架&#xff0c;很多人通過vue官方文檔的學習&#xff0c;對vue的使用都有了一定的了解&#xff0c;但再在項目工程化處理的時候&#xff0c;卻發現不知道改怎么更好的管理自己的項目&#xff0c;如何去引入一些框架以及vue全家桶其他框架的使用&a…

EclipseLink MOXy作為JAXB提供者

EclipseLink MOXy是JAXB提供程序&#xff0c;并且是內置在JDK中的默認JAXB提供程序的引人注目的替代品。 首先是一個簡單的測試&#xff0c;將Java對象編組為XML&#xff1a; 這是模型&#xff1a; XmlRootElement(nameMemberDetailsRequest, namespacehttp://bk.org/members…

monkeyrunner多點觸摸

思路是&#xff1a;在屏幕上某個位置按著不放&#xff1a;device.touch(x,y,md.DOWN) 然后再做一個滑動的操作&#xff1a;device.drap((x1,y1),(x2,y2),0.2,10) 然后再松開按鍵&#xff1a;device.touch(x,y,md.UP) #codeing:utf-8 from com.android.monkeyrunner import Monk…

雅虎前端優化的35條軍規

閱讀目錄 內容部分css部分js部分javascript, css 圖片 cookie移動端 服務器摘要&#xff1a;無論是在工作中&#xff0c;還是在面試中&#xff0c;web前端性能的優化都是很重要的&#xff0c;那么我們進行優化需要從哪些方面入手呢&#xff1f;可以遵循雅虎的前端優化34條軍規&…