JSF基于事件的交流:新派方法

在上一篇文章中 ,我们学习了基于Observer / Event Listener和Mediator模式的基于事件的通信。 由于它们的缺点,我想展示基于事件的通信的更有效方法。 我们将从Google Guava EventBus开始,以CDI (Java EE平台的上下文和依赖注入)结束。

番石榴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) {...}
}
下一步很简单。 要接收事件,对象(bean)应公开一个公共方法,该方法以@Subscribe批注进行批注,该方法接受具有所需事件类型的单个参数。 该对象需要将自身传递给EventBus实例的register()方法。 让我们创建两个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}
}

要发布事件,只需将事件对象提供给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";}}
}
Guava EventBus允许创建对许多不同事件做出反应的任何侦听器,只需使用@Subscribe注释许多方法即可。 侦听器可以利用现有事件层次结构。 因此,如果侦听器A正在等待事件A,并且事件A具有名为B的子类,则此侦听器将接收两种类型的事件:A和B。在我们的示例中,我们发布了三个事件:SettingsChangeEvent,LocaleChangeEvent和TimeZoneChangeEvent。 MyBean1中的handleLocaleChange()方法将仅接收LocaleChangeEvent。 方法handleTimeZoneChange()将仅接收TimeZoneChangeEvent。 但是,请查看MyBean2中的handleSettingsChange()方法。 它将接收所有三个事件!
如您所见,仍然需要手动注册(EventBusProvider.getEventBus()。register(this)),并且在上一篇文章中提到的作用域bean的问题仍然存在。 我们应该注意EventBusProvider的作用域和发布/订阅者bean的作用域。 但是,正如您可能还会看到的,与Mediator模式相比,我们有了一些改进:不需要特殊的接口,没有固定定义订户的方法名,也可以进行多侦听器,不花精力管理注册的实例,等等。但并非最不重要的是-异步AsyncEventBus和对DeadEvent的订阅(用于侦听没有侦听器调度的任何事件-便于调试)。 请按照本指南将现有的基于EventListener的系统转换为基于EventBus的系统。
CDI(上下文和依赖注入)
每个符合JEE 6的应用服务器都支持CDI(JSR-299规范)。 它定义了一组补充服务,可帮助改善应用程序代码的结构。 CDI的最著名的实现是OpenWebBeans和JBoss Weld 。 CDI中的事件允许bean完全不依赖地进行交互。 事件生产者引发事件,这些事件由容器传递给事件观察者。 这个基本架构听起来像熟悉的Observer / Observable模式,但是有很多好处。
  • 事件生产者和事件观察者彼此分离。
  • 观察者可以指定“选择器”的组合来缩小他们将接收的事件通知的范围。
  • 可以立即或延迟通知观察者,直到当前事务结束为止。
  • 使用条件观察者方法进行作用域定义时不会感到头痛(还记得作用域bean和Mediator / EventBus的问题吗?)。
条件观察者方法仅在声明观察者方法的bean范围当前处于活动状态时才允许获取已经存在的bean实例,而无需创建新的bean实例。 如果观察者方法不是有条件的,则将始终创建相应的bean。 您很灵活!
在我看来,CDI事件机制是进行基于事件的交流的最佳方法。 这个问题很复杂。 让我们只显示基本功能。 观察者方法是带有参数@Observes的bean的方法。
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());}
}
容器调用所有观察者方法,并将事件对象作为事件参数的值传递。 如果任何观察者方法引发异常,则容器将停止调用观察者方法,并且该异常将由fire()方法重新抛出。 上面的@Any注释充当所有限定符的别名。 您会看到,无需手动注册观察员。 简单? 在注入点指定其他限定词也很简单:
// 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);}
}
让我们谈谈“条件观察者方法”。 默认情况下,如果当前上下文中没有观察者实例,则容器将实例化观察者以向其传递事件。 这种行为并不总是令人满意的。 我们可能只想将事件传递给当前上下文中已经存在的观察者实例。 通过在@Observes批注中添加receive = IF_EXISTS来指定条件观察者。
public void onLocaleChangeEvent(@Observes(receive = IF_EXISTS) @Updated Locale locale) {...
}
在此处阅读有关范围和上下文的更多信息。 在这篇简短的文章中,我们不能再谈论更多功能,例如“具有成员的事件限定符”和“事务观察者”。 我想鼓励大家开始学习CDI。 玩得开心!
参考: JSF中基于事件的通信。 新学派的方法 。 来自我们的JCG合作伙伴 Oleg Varaksin,来自“软件开发思想”博客。

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

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

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

相关文章

菜鸟之路-浅谈设计模式之单例设计模式

单例设计模式 定义&#xff1a;确保一个类仅仅有一个实例&#xff0c;并且自行实例化并向整个系统提供这个实例。单例模式是一种经常使用的软件设计模式。在它的核心结构中仅仅包括一个被称为单例的特殊类。通过单例模式能够保证系统中一个类仅仅有一个实例并且该实例易于外界訪…

python 32bit数据结构_python实现bitmap数据结构详解

bitmap是很常见的算法设计&#xff0c;例如用以Bloom Filter中&#xff1b;用以无反复整数金额的排列这些。bitmap一般根据数组来完成&#xff0c;数组中每一个原素能够当做是一系列二进制数&#xff0c;全部元素组成更高的二进制结合。针对Python而言&#xff0c;整数金额种类…

MVC如何使用开源分页插件shenniu.pager.js

最近比较忙&#xff0c;前期忙公司手机端接口项目&#xff0c;各种开发调试发布现在几乎上线无问题了&#xff1b;虽然公司项目忙不过在期间抽空做了两件个人觉得有意义的事情&#xff0c;一者使用aspnetcore开发了个人线上项目&#xff08;要说线上其实只能ip访问&#xff0c;…

四. 基于环视Camera的BEV感知算法-PETR

目录 前言0. 简述1. 算法动机&开创性思路2. 主体结构3. 损失函数4. 性能对比5. PETRv2总结下载链接参考 前言 自动驾驶之心推出的《国内首个BVE感知全栈系列学习教程》&#xff0c;链接。记录下个人学习笔记&#xff0c;仅供自己参考 本次课程我们来学习下课程第四章——基…

Java EE 6 VS Spring 3:Java EE已经杀死了Spring? 没门!

介绍 几天前&#xff0c;我在听Java Spotlight Podcast的插曲85 。 在这次演讲中&#xff0c; Bert Ertman和Paul Bakker讨论了从Spring迁移到Java EE。 基本上&#xff0c;在他们的介绍中&#xff0c;他们说&#xff0c;如今&#xff0c;选择Spring而不是Java EE是没有意义的。…

usb检测串口是哪个角_怎样测试串口和串口线是否正常

一步&#xff1a;把串口线或者USB转串口线插到计算机上。二步&#xff1a;打开串口调试助手接着选择串口&#xff0c;串口线和 USB 转串口的端口号查看路径&#xff1a;电脑上--右键--属性--硬件--设备管理器-端口(COM 和LPT),点开端口前面的号查看即可。注释&#xff1a;1、US…

NodeJS常用模块介绍

收集了NodeJS开发中常用的一些模块。MVC框架 - Express Express 是轻量灵活的Nodejs Web应用框架&#xff0c;它可以快速地搭建网站。Express框架建立在Nodejs内置的Http模块上&#xff0c;并对Http模块再包装&#xff0c;从而实际Web请求处理的 功能。它支持多种前端模板&…

Java泛型面试问题

Java面试中的通用面试问题在相当长的时间内在Java 5周围越来越普遍&#xff0c;许多应用程序都转移到Java 5上&#xff0c;并且几乎所有新的Java开发都发生在Tiger&#xff08;Java 5的代号&#xff09;上。 泛型和Java 5功能&#xff08;例如Enum&#xff09;的重要性&#xf…

隐层元素闪一下_太阳一直依靠什么元素在燃烧,地球上的重元素又是怎么来的?...

本文基于回答网友一个这样的问题&#xff1a;太阳目前氢核聚变是氦碳氧稳定燃烧地球上的铁镍重元素哪里来的&#xff1f;可以说&#xff0c;这是一个毫无逻辑乱七八糟的问题&#xff0c;但既然邀请回答&#xff0c;就从中挑出几个稍显合理的问题说明一下。太阳核心每时每刻都在…

基于Token的WEB后台认证机制

基于Token的WEB后台认证机制 几种常用的认证机制 HTTP Basic Auth HTTP Basic Auth简单点说明就是每次请求API时都提供用户的username和password&#xff0c;简言之&#xff0c;Basic Auth是配合RESTful API 使用的最简单的认证方式&#xff0c;只需提供用户名密码即可&#xf…

JSF基于事件的沟通:过时的方法

用JSF编写的Web应用程序由相互交互的bean组成。 在开发Web应用程序时&#xff0c;bean之间的通信是主要的设计模式之一。 有时&#xff0c;一个bean需要向其他bean发送事件&#xff0c;以通知它们某些更改或其他任何更改。 我们通常可以将托管bean或Spring bean注入另一个bean的…

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条军规&…