基于jsf的项目_JSF基于事件的沟通:过时的方法

基于jsf的项目

用JSF编写的Web应用程序由相互交互的bean组成。 在开发Web应用程序时,bean之间的通信是主要的设计模式之一。 有时,一个bean需要将事件发送给其他bean,以通知它们某些更改或其他任何更改。 通常,我们可以将托管bean或Spring 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中Mediator模式的最大缺点可能是它是有作用域的bean。 视图作用域调解器只能与视图作用域的bean一起顺利使用。 当视图作用域调解器被销毁时,注册的视图作用域Bean将自动删除。 其他情况可能会导致内存泄漏或几个问题。 例如,应通过调用removeCollaborator()手动删除由视图作用域介体注册的请求作用域Bean(很容易忘记)。 会话作用域的Bean应该由会话作用域的介体注册,否则销毁视图作用域的介体后,它们将不会得到通知。 等等
实际上,介体模式仅比常规的“观察者/事件监听器”概念好一步。 有更灵活的方法,其中“任何方法”都可以捕获引发的事件,不仅可以修复指定的问题,例如listenToEvent()。 在下一篇文章中,我们将看到简单而简单的方法,如何仅通过一种方法和其他建议来捕获乘法事件。

参考: JSF中基于事件的通信。 我们的JCG合作伙伴 Oleg Varaksin在软件开发思想博客上的老式方法 。


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

基于jsf的项目

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/355095.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

构建XML

构建XML举个小例子 //构建入参xmlDocument document DocumentHelper.createDocument();Element root document.addElement("wss");Element lajgEle root.addElement("wsss");lajgEle.addElement("c").addText(c);lajgEle.addElement("n&…

[CATARCS_2017] Week 1

SAE J1939 1234567891011121314151617181920212223242526272829303132 SoF SIGSRRIDE 1234567891011121314151617181920212223242526272829303132 转载于:https://www.cnblogs.com/cragoncan…

oracle数据库如何写翻页_oracle数据库如何写翻页

{"moduleinfo":{"card_count":[{"count_phone":1,"count":1}],"search_count":[{"count_phone":4,"count":4}]},"card":[{"des":"阿里云数据库专家保驾护航&#xff0c;为用户…

使用Java 8 Lambda简化嵌套循环

对于每个经常需要在Java 8&#xff08;或更高版本&#xff09;中使用多维数组的人来说&#xff0c;这只是一个快速技巧。 在这种情况下&#xff0c;您可能经常以类似于以下代码的结尾&#xff1a; float[][] values ... for (int i 0; i < values.length; i) {for (int …

onpropertychange替代方案

onpropertychange替代方案1.onpropertychange的介绍 onpropertychange事件就是property(属性)change(改变)的时候&#xff0c;触发事件。 这是IE专有的&#xff01; 如果想兼容其它浏览器&#xff0c;有个类似的事件&#xff0c;oninput&#xff01; 可能大家会想到另外一个事…

SQL SERVER的锁机制(二)——概述(锁的兼容性与可以锁定的资源)

二、完整的锁兼容性矩阵(见下图) 对上图的是代码说明&#xff1a;见下图。 三、下表列出了数据库引擎可以锁定的资源。 名称 资源 缩写 编码 呈现锁定时&#xff0c;描述该资源的方式 说明 数据行 RID RID 9 文件编号&#xff1a;分页编号&#xff1a;Slot编号 用于…

vue数组变化视图_vue对象数组数据变化,页面不渲染

data() { // data数据return {arr: [1,2,3],obj:{a: 1,b: 2}};},// 数据更新 数组视图不更新this.arr[0] OBKoro1;this.arr.length 1;console.log(arr);// [OBKoro1];// 数据更新 对象视图不更新this.obj.c OBKoro1;delete this.obj.a;console.log(obj); // {b:2,c:OBKoro1}…

jsp里面编写java代码注意加双引号

jsp里面编写java代码注意加双引号 if("<%type%>""open"){document.getElementById("e").focus();}

angularjs1访问子组件_Vue学习笔记之组件的应用

Vue组件的应用&#xff1a;1、基础使用&#xff1a;第一步创建组件&#xff0c;第二步注册组件&#xff0c;第三步使用组件。在注册组件是需要用到template的属性。全局组件和局部组件组件的嵌套(父子组件)&#xff1a;注意先后顺序&#xff0c;先声明&#xff0c;后面才能用2、…

Qt 程序打包发布总结

1. 概述 当我们用QT写好了一个软件&#xff0c;要把你的程序分享出去的时候&#xff0c;不可能把编译的目录拷贝给别人去运行。编译好的程序应该是一个主程序&#xff0c;加一些资源文件&#xff0c;再加一些动态链接库&#xff0c;高大上一些的还可以做一个安装文件。 QT开发…

什么是activemq_什么是ActiveMQ?

什么是activemq尽管Active MQ网站已经对ActiveMQ进行了详尽的介绍&#xff0c;但我想在其定义中添加更多上下文。 从ActiveMQ项目的网站上&#xff1a; “ ActiveMQ是JMS 1.1的开源实现&#xff0c;是J2EE 1.4规范的一部分。” 这是我的看法&#xff1a;ActiveMQ是一种开源消…

jdk1.8 stream() 把List <String>变成String

jdk1.8 stream() 把List 变成StringList<String> zts ss.getZts(); if (!CollectionUtils.isEmpty(zts)){String zt zts.stream().collect(Collectors.joining(",", "", "")); }就可以变成1,2 这种形式

boost跨平台 c++_跨平台C++整数类型 之一 固定宽度整数(boost和C++11)

原来一直使用ACE的跨平台整数类型&#xff0c;比如&#xff1a;ACE_UINT32, 但是自己使用C的风格是明显的现代风格&#xff0c;以范型为主&#xff0c;所以最近开始逐步替换ACE的代码&#xff0c;改用boost库。在boost库中&#xff0c;standard integer types用来支持跨平台的整…

FTP服务器原理

21.1 FTP服务器原理使用明码传输方式&#xff0c;且有相当多的安全危机历史。因此一般使用功能较少的vsftpd这个软件。21.1.1 FTP功能简介有以下功能文档传输与管理不同等级的用户身份&#xff1a;user&#xff0c;guest&#xff0c;anonymous命令记录与登录文件记录限制用户活…

jdk1.8 stream() 把List<Map<String,Object>> 变成Map<Object, List<Map<String, Object>>>

jdk1.8 stream() 把List<Map<String,Object>> 变成Map<Object, List<Map<String, Object>>>List<Map<String,Object>> list jdbc.queryForList(sql); Map<Object, List<Map<String, Object>>> map list.stream(…

java对两个表进行排序_Excel工作簿中多个worksheet工作表,如何对工作表进行排序?...

案例&#xff1a;如下图所示&#xff0c;一个Excel文件中&#xff0c;包含了多个工作表&#xff0c;有1-雷哥office&#xff0c;2-雷哥office......但是&#xff0c;我们发现工作表的顺序是比较混乱的&#xff0c;为了方便管理&#xff0c;如何对工作表进行排序呢&#xff1f;方…

mysql5.7用户管理

添加用户 命令&#xff1a;create user usernamehost identified by password 例子&#xff1a;create user changfeng% identified by 111111 配置用户权限 命令&#xff1a;grant privileges on database.table to usernamehost 例子&#xff1a;grant all on *.* to changfe…

jdk1.8 stream() 把List对象 变成String

jdk1.8 stream() 把List对象 变成StringString dm list.stream().map(XXX -> XXX.getDm()).collect(Collectors.joining(",", "", ""));有时候获取到一个List<XXX>(XXX是对象),因为业务需求,我们想要获取其中一个属性&#xff0c;变成…

Spring Cloud Ribbon –进行安全呼叫

很简单&#xff0c;但是最近我为此感到困惑 –我必须对安全的远程服务进行基于Netflix Ribbon的客户端调用。 事实证明&#xff0c;使用Netflix Ribbon可以通过两种方式实现这一点&#xff0c;我将通过Spring Cloud对Ribbon库的出色支持来演示这一点。 在之前的两个博客文章中…

python、中循环功能可通过什么命令实现_python定时执行指定函数的方法 Python如何定时循环执行命令?...

python中如何定时执行某一个函数 怎么连接。。先调用注册函数 然后调用登录函数就行。顺序执行。至于如果你说注册失败不进行登录的话 直接在注册函数里面处理 注册失败 return def sign_up(user,pwd): #注册代码... # if not sign_up_true: # 注册失败 返回false return fals如…