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

用JSF編寫的Web應用程序由相互交互的bean組成。 在開發Web應用程序時,bean之間的通信是主要的設計模式之一。 有時,一個bean需要向其他bean發送事件,以通知它們某些更改或其他任何更改。 我們通常可以將托管bean或Spring bean注入另一個bean的屬性中,以便另一個bean可以直接通知注入的bean。 注入是好的,但是它并不是出于交流目的而引入的。 它與動態的松散耦合系統相距甚遠,在該系統中,每個bean都不了解其他bean。 在松耦合系統中,我們需要一種基于事件的良好通信機制。 這篇文章將涵蓋兩種設計模式:觀察者/事件監聽器和中介者模式。 這些模式如今已在許多Web應用程序中廣泛使用,但是它們具有缺點。 該系統并不是真正與它們松散耦合。 有很多更好的現代方法。 因此,我在帖子名稱中寫了“ Old-school approach”。 新學校的方法將在下一篇文章中公開。

觀察員/事件聽眾
?

我們將從觀察者(也稱為事件監聽器)模式開始。 一個稱為主題或可觀察對象的對象會維護其依賴項的列表(稱為觀察者),并自動將狀態變化通知他們。 在Java中,有一些類java.util.Observer和java.util.Observable可以幫助實現此模式。 通過此模式進行的基于事件的通信的其他相關構造是類java.util.EventObject和接口java.util.EventListener。 讓我們開始編碼。 假設我們有一個I18N Web應用程序,并且用戶可以在用戶設置中的某處選擇一種語言(語言環境)。 假設我們有一個名為UserSettingsForm的bean,它負責用戶設置。 某些會話作用域的Bean可以保留I18N文本/消息,因此,當用戶更改當前語言時,需要以最后選擇的語言重置以前的文本/消息。 首先,我們需要一個LocaleChangeEvent。
public class LocaleChangeEvent extends EventObject {Locale locale;public LocaleChangeEvent(Object source, Locale locale) {super(source);this.locale = locale;}public Locale getLocale() {return locale;}
}

其次,我們需要一個接口LocaleChangeListener。

public interface LocaleChangeListener extends EventListener {void processLocaleChange(LocaleChangeEvent event);
}
我們的UserSettingsForm現在可以通過注冊字符串并通知它們來管理LocaleChangeListener類型的實例。
@ManagedBean
@SessionScoped
public class UserSettingsForm implements Serializable {private Locale selectedLocale;private List<SelectItem> locales;private List<LocaleChangeListener> localeChangeListeners = new ArrayList<LocaleChangeListener>();public void addLocaleChangeListener(LocaleChangeListener listener) {localeChangeListeners.add(listener);}public void localChangeListener(ValueChangeEvent e) {...// notify listenersLocaleChangeEvent lce = new LocaleChangeEvent(this, this.selectedLocale);for (LocaleChangeListener lcl : localeChangeListeners) {lcl.processLocaleChange(lce);}}...
}
方法localChangeListener()是JSF ValueChangeListener,可以在例如h:selectOneMenu中應用。 每個實現LocaleChangeListener的bean都應該由UserSettingsForm注冊,以便通過語言環境更改得到通知。
@ManagedBean
@SessionScoped
public MyBean implements LocaleChangeListener, Serializable {// UserSettingsForm can be injected e.g. via @ManagedProperty annotation or via Spring facilityprivate UserSettingsForm userSettingsForm;@PostConstructpublic void initialize() {userSettingsForm.addLocaleChangeListener(this);}public void processLocaleChange(LocaleChangeEvent event) {// reset something related to I18N data...}
}

就觀察者模式而言,UserSettingsForm是可觀察的,而LocaleChangeListener的實例(如MyBean)則是觀察者。 討論的模式帶有一些您需要注意的重要問題。 豆緊密耦合。 有很多手動工作來重新注冊bean。 Bean必須實現定義的接口。 如果您有100個語義不同的更改通知了bean,則它必須實現100個接口。 無法通知已注冊的偵聽器的子集–即使不需要通知所有偵聽器,也總是會通知他們。 最后但并非最不重要的– 內存管理問題 。 馬丁·福勒(Martin Fowler)寫道: “假設我們有一些觀察某些域對象的屏幕。 關閉屏幕后,我們希望將其刪除,但是域對象實際上通過觀察者關系攜帶了對屏幕的引用。 在內存管理的環境中,壽命長的域對象可能會占據很多僵尸屏幕,從而導致大量內存泄漏。”

調解員
?

與“觀察者/事件偵聽器”模式相比,“中介者”模式改善了基于事件的通信。 使用中介者模式,對象之間的通信將與中介者對象一起封裝。 對象不再彼此直接通信,而是通過調解器進行通信。 這減少了通信對象之間的依賴性。 我們將看到它如何用于JSF-Spring Bean(在上面的示例中是標準托管Bean)。 我們將實現一個Mediator類來管理作用域bean之間的通信。 重要的是要理解一個bean只能通知范圍更廣的另一個bean。 視圖作用域的bean可以通知視圖作用域的會話,會話作用域和應用程序作用域的bean,但不能請求作用域較小的作用域的bean。 請遵循此規則以避免麻煩。 這是作用域Bean的一種特性–您可能還記得,可以始終將作用域更廣的bean注入到作用域更窄的bean中,反之亦然。 為了開始使用Mediator,我們將引入兩個接口MediatorEvent,MediatorListener和中心類Mediator。
public interface MediatorEvent {...
}public interface MediatorListener {public void listenToEvent(MediatorEvent event);
}public class Mediator implements Serializable {private Collection<MediatorListener> collaborators = new HashSet<MediatorListener>();public static Mediator getCurrentInstance() {// access Mediator bean by JSF-Spring facilityreturn ContextLoader.getCurrentWebApplicationContext().getBean("mediator");}public void fireEvent(MediatorEvent event) {for (MediatorListener mediatorListener : collaborators) {mediatorListener.listenToEvent(event);}}public void addCollaborator(MediatorListener collaborator) {collaborators.add(collaborator);}public void removeCollaborator(MediatorListener collaborator) {collaborators.remove(collaborator);}
}
介體是一個有作用域的bean,可以注冊并通知協作者。 協作者通過調解員進行注冊。 在Spring中,bean可以實現接口InitializingBean,以便在bean實例化之后自動調用afterPropertiesSet()方法。 這類似于@PostConstruct。 afterPropertiesSet()是此類bean通過介體注冊的正確位置。 Bean還應該實現MediatorListener以便被通知(請參見listenToEvent())。
public MyBean implements MediatorListener, InitializingBean, Serializable {public void afterPropertiesSet() throws Exception {...Mediator.getCurrentInstance().addCollaborator(this);}@Overridepublic void listenToEvent(MediatorEvent event) {if (event instanceof LocaleChangeEvent) {// do something}}
}
我們將在UserSettingsForm和區域設置更改中使用相同的方案。 由Mediator注冊的Bean將通過fireEvent()進行通知。
public class LocaleChangeEvent implements MediatorEvent {...
}public class UserSettingsForm implements Serializable {private Locale selectedLocale;private List<SelectItem> locales;public void localChangeListener(ValueChangeEvent e) {...// notify listenersMediator.getCurrentInstance().fireEvent(new LocaleChangeEvent(this, this.selectedLocale));}...
}
調解器模式提供了豆之間更好的耦合,但是它們仍與調解器耦合。 進一步的缺點:仍然需要手動注冊bean –請參見附加代碼Mediator.getCurrentInstance()。addCollaborator(this)。 每個bean仍應至少實現一個MediatorListener,這會帶來另一個約束– listenToEvent()。 每個bean都應實現此接口方法! JSF中介體模式的最大缺點可能是它是有作用域的bean。 視圖作用域調解器只能與視圖作用域的bean一起順利使用。 當視圖作用域調解器被銷毀時,注冊的視圖作用域Bean將自動刪除。 其他情況可能會導致內存泄漏或幾個問題。 例如,應該通過調用removeCollaborator()手動刪除由視圖作用域介體注冊的請求作用域Bean(很容易忘記)。 會話作用域的Bean應該由會話作用域的介體注冊,否則銷毀視圖作用域的介體后,它們將不會得到通知。 等等
實際上,中介器模式僅比常規的“觀察者/事件偵聽器”概念好一步。 有更靈活的方法,其中“任何方法”都可以捕獲引發的事件,而不僅可以修復指定的問題,例如listenToEvent()。 在下一篇文章中,我們將看到簡單而簡單的方法,如何僅通過一種方法和其他建議來捕獲乘法事件。

參考: JSF中基于事件的通信。 我們的JCG合作伙伴 Oleg Varaksin在“ 軟件開發思想”博客上的過時做法 。


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

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

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

相關文章

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條軍規&…

stm32 內部sram大小_在SRAM、FLASH中調試代碼的配置方法(附詳細步驟)

聊天界面發送嵌入式大雜燴獲取1TB大雜燴資料包STM32的FLASH擦寫次數有限(大概為1萬次)&#xff0c;所以為了延長FLASH的使用時間&#xff0c;我們平時調試時可以選擇在SRAM中進行硬件調試。除此之外&#xff0c;SRAM 存儲器的寫入速度比在內部 FLASH 中要快得多&#xff0c;所以…

Spring Profile模式示例

最近&#xff0c;我們介紹了Spring Profiles的概念。 此概念是針對不同部署環境的輕松配置區分符。 直接的用例&#xff08;已提出&#xff09;是對相關類進行注釋&#xff0c;以便Spring根據活動的配置文件加載適當的類。 但是&#xff0c;這種方法可能并不總是適用于常見的…

Android 樣式 (style) 和主題(theme)

轉載&#xff1a;https://gold.xitu.io/post/58441c48c59e0d0056a30bc2 樣式和主題 樣式是指為 View 或窗口指定外觀和格式的屬性集合。樣式可以指定高度、填充、字體顏色、字號、背景色等許多屬性。 樣式是在與指定布局的 XML 不同的 XML 資源中進行定義。 Android 中的樣式與…

自定義控件_VIewPager顯示多個Item

一直以來想搞明白這個不完全的VIewPager是怎么做到的&#xff0c;有幸看到這片篇文章 有二種實現方法 1.設置的屬性 1.clipChildren屬性 2.setPageMargin 3.更新Item外界面 2.重寫getPageWidth public class MultiplePagerAdapter extends PagerAdapter { private List<I…

華為怎么改輸入法皮膚_微信和QQ個性鍵盤皮膚

hello大家好&#xff0c;今天是2019年1月1號&#xff0c;祝大家新年快樂今天是新年的第一天&#xff0c;所以說給大家介紹一個好玩的&#xff0c;微信和QQ都能設置的個性的鍵盤皮膚&#xff0c;看下圖&#xff0c;這樣的個性的鍵盤主題怎么設置呢&#xff1f;其實很簡單&#x…

EasyMock教程–入門

在本文中&#xff0c;我將向您展示EasyMock是什么&#xff0c;以及如何使用它來測試Java應用程序。 為此&#xff0c;我將創建一個簡單的Portfolio應用程序&#xff0c;并使用JUnit&#xff06;EasyMock庫對其進行測試。 在開始之前&#xff0c;讓我們首先了解使用EasyMock的需…

synchronized內置鎖

synchronized內置鎖&#xff0c;如果發生阻塞&#xff0c;無法被中斷&#xff0c;除非關閉jvm.因此不能從死鎖中恢復。轉載于:https://www.cnblogs.com/paulbai/p/6163250.html

如何加快Json 序列化?有哪些方法?

1、使用阿里的fastjson 2、可以通過去除不必要屬性加快序列化。如person對象&#xff0c;有id&#xff0c;name&#xff0c;address&#xff0c;我json需要用戶姓名&#xff0c;此時序列化的時候就只序列化name&#xff0c;id和address不序列化。轉載于:https://www.cnblogs.co…

用金萬維怎么設置路由器_家用路由器怎么設置 家庭路由器設置方法【圖文】...

這里以TP-link的無線路由器為例&#xff0c;教一下怎么調試路由器上網。準備工具:網線兩條&#xff0c;電腦或者手機&#xff0c;用手機的話就不需要用網線了1、用網線連接光纖貓與路由器&#xff0c;光貓的LAN1口與路由器的WAN相連。路由器的LAN任意一個口用網線連接電腦。2、…

Liferay –簡單主題開發

實際上&#xff0c;Liferay的6.1版本已經走了很長一段路&#xff0c;該版本完全支持JSF和IceFaces。 我的目標是使它成為我們團隊中的標準協作工具&#xff0c;因此我仍在嘗試學習它的精髓。 好的軟件應用程序可以解決問題&#xff0c;但是好的軟件應用程序不僅可以解決問題&am…

springmvc初步配置

導包/添加依賴&#xff1a;<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.springfram…