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.mzph.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…