番石榴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) {...}
}
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";}}
}
- 事件生產者和事件觀察者彼此分離。
- 觀察者可以指定“選擇器”的組合來縮小他們將接收的事件通知的范圍。
- 可以立即或延遲通知觀察者,直到當前事務結束為止。
- 使用條件觀察者方法進行作用域定義時不會感到頭痛(還記得作用域bean和Mediator / EventBus的問題嗎?)。
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());}
}
// 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);}
}
public void onLocaleChangeEvent(@Observes(receive = IF_EXISTS) @Updated Locale locale) {...
}
翻譯自: https://www.javacodegeeks.com/2012/07/jsf-event-based-communication-new.html