javascript
JSF基于事件的交流:新派方法
番石榴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的問題嗎?)。
如果觀察者方法僅對限定的事件感興趣,則事件參數也可以指定限定符-這些事件具有限定符。
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
總結
以上是生活随笔為你收集整理的JSF基于事件的交流:新派方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电脑上2018wps(下载wps文件)
- 下一篇: Java EE 6 VS Spring