javascript
基于jsf的项目_JSF基于事件的交流:新派方法
基于jsf的項(xiàng)目
在上一篇文章中 ,我們學(xué)習(xí)了基于Observer / Event Listener和Mediator模式的基于事件的通信。 由于它們的缺點(diǎn),我想展示基于事件的通信的更有效方法。 我們將從Google Guava EventBus開(kāi)始,最后以CDI (Java EE平臺(tái)的上下文和依賴注入)結(jié)束。番石榴EventBus
Google Guava庫(kù)具有有用的package eventbus 。 EventBus類允許組件之間進(jìn)行發(fā)布-訂閱式通信,而無(wú)需組件之間進(jìn)行顯式注冊(cè)。 因?yàn)槲覀冮_(kāi)發(fā)Web應(yīng)用程序,所以應(yīng)該將此類的實(shí)例封裝在有作用域的bean中。
讓我們編寫(xiě)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;} }我僅以一個(gè)示例來(lái)演示Guava EventBus的所有主要功能。 讓我們編寫(xiě)以下事件層次結(jié)構(gòu):
public class SettingsChangeEvent {}public class LocaleChangeEvent extends SettingsChangeEvent {public LocaleChangeEvent(Object newLocale) {...} }public class TimeZoneChangeEvent extends SettingsChangeEvent {public TimeZoneChangeEvent(Object newTimeZone) {...} } 下一步很簡(jiǎn)單。 要接收事件,對(duì)象(bean)應(yīng)公開(kāi)一個(gè)公共方法,該方法以@Subscribe批注進(jìn)行批注,該方法接受具有所需事件類型的單個(gè)參數(shù)。 該對(duì)象需要將自身傳遞給EventBus實(shí)例的register()方法。 讓我們創(chuàng)建兩個(gè)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} }要發(fā)布事件,只需將事件對(duì)象提供給EventBus實(shí)例的post()方法。 EventBus實(shí)例將確定事件的類型,并將其路由到所有已注冊(cè)的偵聽(tīng)器。
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允許創(chuàng)建對(duì)許多不同事件做出React的任何偵聽(tīng)器,只需使用@Subscribe注釋許多方法即可。 偵聽(tīng)器可以利用現(xiàn)有事件層次結(jié)構(gòu)。 因此,如果偵聽(tīng)器A正在等待事件A,并且事件A具有名為B的子類,則此偵聽(tīng)器將接收兩種類型的事件:A和B。在我們的示例中,我們發(fā)布了三個(gè)事件:SettingsChangeEvent,LocaleChangeEvent和TimeZoneChangeEvent。 MyBean1中的handleLocaleChange()方法將僅接收LocaleChangeEvent。 方法handleTimeZoneChange()將僅接收TimeZoneChangeEvent。 但是,請(qǐng)查看MyBean2中的handleSettingsChange()方法。 它將接收所有三個(gè)事件! 如您所見(jiàn),仍然需要手動(dòng)注冊(cè)(EventBusProvider.getEventBus()。register(this)),并且在上一篇文章中提到的作用域bean的問(wèn)題仍然存在。 我們應(yīng)該注意EventBusProvider的作用域和發(fā)布/訂閱者bean的作用域。 但是,正如您可能還會(huì)看到的,與Mediator模式相比,我們有了一些改進(jìn):不需要特殊的接口,沒(méi)有固定定義訂戶的方法名,也可以進(jìn)行多偵聽(tīng)器,不費(fèi)力氣來(lái)管理注冊(cè)的實(shí)例,等等。但并非最不重要的是-異步AsyncEventBus和對(duì)DeadEvent的訂閱(用于偵聽(tīng)沒(méi)有偵聽(tīng)器調(diào)度的任何事件-便于調(diào)試)。 請(qǐng)按照本指南將現(xiàn)有的基于EventListener的系統(tǒng)轉(zhuǎn)換為基于EventBus的系統(tǒng)。 CDI(上下文和依賴注入) 每個(gè)符合JEE 6的應(yīng)用服務(wù)器均支持CDI(JSR-299規(guī)范)。 它定義了一組補(bǔ)充服務(wù),可幫助改善應(yīng)用程序代碼的結(jié)構(gòu)。 CDI的最著名實(shí)現(xiàn)是OpenWebBeans和JBoss Weld 。 CDI中的事件允許bean完全不依賴地進(jìn)行交互。 事件生產(chǎn)者引發(fā)事件,這些事件由容器傳遞給事件觀察者。 這個(gè)基本架構(gòu)聽(tīng)起來(lái)像是熟悉的Observer / Observable模式,但是有很多好處。- 事件生產(chǎn)者和事件觀察者彼此分離。
- 觀察者可以指定“選擇器”的組合來(lái)縮小他們將接收的事件通知的范圍。
- 可以立即或延遲通知觀察者,直到當(dāng)前事務(wù)結(jié)束為止。
- 使用條件觀察者方法進(jìn)行作用域定義時(shí)不會(huì)感到頭痛(還記得作用域bean和Mediator / EventBus的問(wèn)題嗎?)。
如果觀察者方法僅對(duì)限定的事件感興趣,則事件參數(shù)也可以指定限定符-這些是具有那些限定符的事件。
public void onLocaleChangeEvent(@Observes @Updated Locale locale) {... }事件限定符只是使用@Qualifier定義的普通限定符。 這是一個(gè)例子:
@Qualifier @Target({FIELD, PARAMETER}) @Retention(RUNTIME) public @interface Updated {}事件生產(chǎn)者使用參數(shù)化Event接口的實(shí)例來(lái)觸發(fā)事件。 該接口的實(shí)例通過(guò)注入獲得。 生產(chǎn)者通過(guò)調(diào)用Event接口的fire()方法并傳遞事件對(duì)象來(lái)引發(fā)事件。
public class UserSettingsForm implements Serializable {@Inject @Any Event<Locale> localeEvent;public void localeChangeListener(ValueChangeEvent e) {// notify all observerslocaleEvent.fire((Locale)e.getNewValue());} } 容器調(diào)用所有觀察者方法,并將事件對(duì)象作為事件參數(shù)的值傳遞。 如果任何觀察者方法引發(fā)異常,則容器將停止調(diào)用觀察者方法,并且該異常將由fire()方法重新拋出。 上面的@Any批注充當(dāng)所有限定符的別名。 您會(huì)看到,無(wú)需手動(dòng)注冊(cè)觀察員。 簡(jiǎn)單? 在注入點(diǎn)指定其他限定詞也很簡(jiǎn)單: // this will raise events to observers having parameter @Observes @Updated Locale @Inject @Updated Event<Locale> localeEvent; 您還可以具有多個(gè)事件限定符。 該事件被傳遞給每個(gè)具有事件參數(shù)的觀察者方法,該事件參數(shù)可以分配事件對(duì)象,并且除了與事件注入點(diǎn)指定的事件限定符匹配的事件限定符之外,沒(méi)有任何事件限定符。 觀察者方法可能具有其他參數(shù),這些參數(shù)是注入點(diǎn)。 例: public void onLocaleChangeEvent(@Observes @Updated Locale locale, User user) {... }動(dòng)態(tài)指定限定符怎么辦? CDI允許通過(guò)AnnotationLiteral獲得適當(dāng)?shù)南薅ǚ麑?shí)例。 這樣,我們可以將限定符傳遞給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);} } 讓我們談?wù)劇皸l件觀察者方法”。 默認(rèn)情況下,如果當(dāng)前上下文中沒(méi)有觀察者實(shí)例,則容器將實(shí)例化觀察者以向其傳遞事件。 這種行為并不總是令人滿意的。 我們可能只想將事件傳遞給當(dāng)前上下文中已經(jīng)存在的觀察者實(shí)例。 通過(guò)在@Observes批注中添加receive = IF_EXISTS來(lái)指定條件觀察者。 public void onLocaleChangeEvent(@Observes(receive = IF_EXISTS) @Updated Locale locale) {... } 在此處閱讀有關(guān)范圍和上下文的更多信息。 在這篇簡(jiǎn)短的文章中,我們不能再談?wù)摳喙δ?#xff0c;例如“具有成員的事件限定符”和“事務(wù)觀察者”。 我想鼓勵(lì)大家開(kāi)始學(xué)習(xí)CDI。 玩得開(kāi)心! 參考: JSF中基于事件的通信。 新學(xué)派的方法 。 來(lái)自我們的JCG合作伙伴 Oleg Varaksin,來(lái)自“軟件開(kāi)發(fā)思想”博客。翻譯自: https://www.javacodegeeks.com/2012/07/jsf-event-based-communication-new.html
基于jsf的項(xiàng)目
總結(jié)
以上是生活随笔為你收集整理的基于jsf的项目_JSF基于事件的交流:新派方法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 三点水加累读什么 三点水加累到底念啥
- 下一篇: 为什么手机定位不准确