Spring事件的观察者模式

介绍

观察者模式的本质是“定义对象之间的一对多依赖关系,以便当一个对象改变状态时,其所有依赖关系都会得到通知并自动更新。” GoF。 观察者模式是发布/订阅模式的子集,它允许许多观察者对象查看事件。

可以在不同的情况下使用此模式,但总而言之,可以说观察者模式可以在对象应该能够将消息通知其他对象并且您不希望这些对象紧密耦合时应用。 就我而言,当异步事件应通知一个或多个图形组件时,我使用了这种模式。

可以使用临时解决方案或使用java.util.Observer/Observable类来实现此模式。 但是我的项目总是用Spring开发的,无论是Web还是桌面应用 。 因此,在当前文章中,我将解释如何使用Spring实现Observer模式。

手扶

Spring ApplicationContext中的事件处理是通过ApplicationEvent类和ApplicationListener接口提供的。 如果将实现ApplicationListener接口的bean部署到上下文中,则每次将ApplicationEvent发布到容器时, ApplicationListener都会接收到它。
Spring带有内置事件,例如ContextStartedEventContextStoppedEvent ,但是您也可以创建自己的自定义事件。

为了开发自己的事件,需要三个类, 观察者角色, 可观察角色和事件观察者是那些接收事件并且必须实现ApplicationListener类的人。 可观察类负责发布事件,并且必须实现ApplicationEventPublisherAware 。 最后, 事件类必须扩展ApplicationEvent

编码

我要实现的是Observer模式的Wikipedia示例( http://en.wikipedia.org/wiki/Observer_pattern#Example ),但是使用Spring Events而不是Observer / Observable Java类。 该示例是一个基本的发布/订阅示例,其中一个String消息从一个模块发送到另一个模块。
让我们创建MessageEvent 。 此事件包含一个String,它表示我们要发送的消息。 这是一个从ApplicationEvent扩展的简单类。

public class MessageEvent extends ApplicationEvent {*** *private static final long serialVersionUID = 5743058377815147529L;private String message;public MessageEvent(Object source, String message) {super(source);this.message = message;}@Overridepublic String toString() {StringBuilder builder = new StringBuilder();builder.append('MessageEvent [message=').append(message).append(']');return builder.toString();}}

下一个类是Observable类。 此类必须实现ApplicationEventPublisherAware 。 此接口使用ApplicationEventPublisher作为参数定义了一个setter方法。 此参数用于发布事件。
在当前的实现中,该代码还实现了Runnable接口,因此用户可以从控制台输入中进行创建,

public class EventSource implements Runnable, ApplicationEventPublisherAware {private ApplicationEventPublisher applicationEventPublisher = null;public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {this.applicationEventPublisher = applicationEventPublisher;}public void run() {final InputStreamReader isr = new InputStreamReader(System.in);final BufferedReader br = new BufferedReader(isr);while (true) {try {String response = br.readLine();System.out.println(Thread.currentThread().getName());this.applicationEventPublisher.publishEvent(new MessageEvent(this, response));} catch (IOException e) {e.printStackTrace();}}}}

Observer类甚至更简单。 实现ApplicationListener接口。 发布事件时将调用onApplicationEvent方法。 看到它是一个通用接口,因此不需要强制转换。 这不同于java.util.Observer类。

public class ResponseHandler implements ApplicationListener<MessageEvent> {public void onApplicationEvent(MessageEvent messageEvent) {System.out.println(Thread.currentThread().getName());System.out.println(messageEvent);}}

在应用程序上下文文件中,您同时注册了ApplicationListenerApplicationEventPublisherAware Bean。

最后是一个主类来测试系统。 创建一个线程以执行多个异步事件。

public class MyApp {public static void main(String args[]) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext('classpath:META-INFspringapp-context.xml');EventSource eventSource = applicationContext.getBean('eventSource', EventSource.class);Thread thread = new Thread(eventSource);thread.start();}}

因此,启动程序并编写一些内容以进行控制台。 您将看到类似以下内容:
你好 Thread-0 Thread-0 MessageEvent [message = hello]
我输入了“ hello ”消息,并打印了事件发布者的线程名 。 然后发送事件并打印处理程序线程名称 。 最后显示接收到的事件。 有一件事情应该引起您的注意。 发送者( Observable )和接收者( Observer )都在同一线程中执行; 默认情况下,事件侦听器同步接收事件。 这意味着publishEvent()方法将阻塞,直到所有侦听器都已完成对事件的处理为止。 这种方法有很多优点(例如,重用事务上下文等),但是在某些情况下,您希望每个事件都在新线程中执行, Spring也支持此策略。

Spring中 ,负责事件管理的类是SimpleApplicationEventMulticaster 。 此类将所有事件多播到所有注册的侦听器,让侦听器忽略它们不感兴趣的事件。默认行为是在调用线程中调用所有侦听器。

现在,我将解释如何初始化Spring Event Architecture以及如何进行修改。 默认情况下,当ApplicationContext 启动后,它将调用initApplicationEventMulticaster方法。 此方法验证是否存在与类型ApplicationEventMulticaster的ID applicationEventMulticaster的bean。 如果是这样,则使用已定义的ApplicationEventMulticaster ,否则,将创建具有默认配置的新SimpleApplicationEventMulticaster

SimpleApplicationEventMulticaster具有可用于指定哪些java.util.concurrent.Executor将执行事件setTaskExecutor。 因此,如果您希望每个事件在不同的线程中执行,那么一个好的方法是使用ThreadPoolExecutor 。 如上一段所述,现在我们必须显式定义SimpleApplicationEventMulticaster而不是 使用默认的。 让我们实现:

<beans xmlns='http:www.springframework.orgschemabeans' xmlns:xsi='http:www.w3.org2001XMLSchema-instance' xmlns:context='http:www.springframework.orgschemacontext' xmlns:task='http:www.springframework.orgschematask' xsi:schemaLocation='http:www.springframework.orgschematask http:www.springframework.orgschemataskspring-task-3.0.xsd http:www.springframework.orgschemabeans http:www.springframework.orgschemabeansspring-beans-3.0.xsd http:www.springframework.orgschemacontext http:www.springframework.orgschemacontextspring-context-3.0.xsd'><bean id='eventSource' class='org.asotobu.oo.EventSource' > <bean id='responseHandler' class='org.asotobu.oo.ResponseHandler' > <task:executor id='pool' pool-size='10' > <bean id='applicationEventMulticaster'        class='org.springframework.context.event.SimpleApplicationEventMulticaster'><property name='taskExecutor' ref='pool' > <bean><beans>

首先,必须将SimpleApplicationEventMulticaster定义为ID为applicationEventMulticaster的bean。 然后设置任务池,然后我们重新运行主类。 输出将是:
你好 线程1 池1 MessageEvent [message = hello]
请注意,现在发送方和接收方线程有所不同。

当然,您可以为更复杂的操作创建自己的ApplicationEventMulticaster 。 您只需要实现ApplicationEventMulticaster并使用applicationEventMulticaster bean名称定义它,事件将根据您自己的策略执行。

希望现在您的Spring桌面应用程序可以充分利用Spring事件来分隔模块。

下载代码。

参考:来自JCG合作伙伴 Alex Soto的Spring Events观察者模式,来自One Jar To Rule All All博客。


翻译自: https://www.javacodegeeks.com/2012/08/observer-pattern-with-spring-events.html

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

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

相关文章

jQuery选择什么版本 1.x? 2.x? 3.x?

目前jQuery有三个大版本&#xff1a; 1.x&#xff1a;兼容ie678,使用最为广泛的&#xff0c;官方只做BUG维护&#xff0c;功能不再新增。因此一般项目来说&#xff0c;使用1.x版本就可以了&#xff0c;最终版本&#xff1a;1.12.4 (2016年5月20日)2.x&#xff1a;不兼容ie678&a…

Delta DVP 系列 PLC 各装置 Modbus 地址

此Modbus地址表以 1 为基础地址 Device Range Type DVP address (Hex) Modbus address (Dec) Effective ES/EX/SS SA/SX/SC EH S 000~255 bit 0000~00FF 000001~000256 0~127 0~1024 0~1024 S 256~511 bit 0100~01FF 000247~000512 S 512~767 bit 020…

Reporting Service 2008 “报表服务器数据库内出错。此错误可能是因连接失败、超时或数据库中磁盘空间不足而导致的”...

今天遇到了两个关于Reporting Service的问题&#xff0c; 出现问题的环境为Microsoft SQL Server 2008 R2 (SP2) - 10.50.4000.0 (X64) 。具体情况请见下面描述。 1&#xff1a;在修改报表的订阅后&#xff0c;保存时出现下面错误&#xff1a; 提示&#xff1a;报表服务器数据库…

Java 7:HashMap与ConcurrentHashMap

从我过去有关性能的文章和HashMap案例研究中可能已经看到&#xff0c;Java线程安全性问题可以很轻松地使Java EE应用程序和Java EE容器崩溃。 在对Java EE性能问题进行故障排除时&#xff0c;我观察到的最常见问题之一是由非线程安全的HashMap get&#xff08;&#xff09;和pu…

计算机网络按信息传输介质的性能来划分,大学计算机基础练习题网络技术.doc...

网络技术一、单选&#xff1a;1. 在计算机网络中&#xff0c;表征数据传输可靠性的指标是( )。A?误码率 B?频带利用率C?信道容量 D?传输速率参考答案&#xff1a;A2. 和通信网络相比&#xff0c;计算机网络最本质的功能是( )。A?数据通信 B?资源共享C?提高计算机的可靠性…

【2017-03-02】集合、结构体、枚举

集合和数组的差别&#xff1a; 数组&#xff1a;同一类型&#xff0c;固定长度集合&#xff1a;不同类型&#xff0c;不固定长度 一、普通集合&#xff08;弱类型&#xff09; 1、ArryList 使用集合首先要引用命名空间。 或者在ArryList上右键找“解析”。 2、集合的定义&#…

Hibernate懒/急加载示例

这篇文章将重点讨论为什么以及如何在应用程序中使用称为LAZY和EAGER加载的概念&#xff0c;以及如何使用Spring的休眠模板以EAGER方式加载LAZY实体。 当然&#xff0c;正如标题本身所暗示的那样&#xff0c;我们将通过一个示例来说明这一点。 场景就是这样&#xff1b; 您是一…

读者使用计算机终端是指,全国2010年10月自学考试管理系统中计算机应用真题及答案...

A.上级模块向下级模块传递控制信号B.下级模块对上级模块传递控制信号C.同级模块之间传递数据或控制信号D.上级模块向下级模块传递数据信号18.“客户”数据表结构为&#xff1a;客户编号、手机号、购物金额&#xff0c;合理的字段类型为( )A.字符型&#xff0c;字符型&#xff0…

软件测试HW02-------fault error failure

程序一 问题一&#xff1a;i应该>0&#xff1b; 问题二&#xff1a; x为空 问题三&#xff1a;test x[2, 3, 5]; y 3;问题四:test: x[2]; y 3&#xff1b;程序二问题一&#xff1a;循环应该反过来;问题二&#xff1a;无;问题三&#xff1a;test:x[1];问题四:test: x[1,2,3…

Mathematica图片局部变色

这篇博客来源于Stack-Exchange上的一个帖子&#xff0c;问题描述如下&#xff1a;如何将图中的红球变为蓝球&#xff1f; 这个问题下面有很多答案&#xff0c;我选了最好的一个答案&#xff0c;代码如下 img Import["C:/Users/1/Desktop/red.jpg"]; getReds[x_Image…

在WebLogic 12c上运行RichFaces

我最初以为我可以在几个月前写这篇文章。 但是我最终被不一样的事情所淹没。 其中之一是&#xff0c;它无法像我在4.0版本中那样简单地启动RichFaces展示柜。 有了所有的JMS magic和不同的提供者检查&#xff0c;这已经成为简单构建和部署它的挑战。 无论如何&#xff0c;我愿意…

Spring Boot系列教程一:Eclipse安装spring-tool-suite插件

一.前言 一直使用eclipse&#xff0c;个人习惯选用Eclipsespring-tool-suite进行开发&#xff0c;特别注意Eclipse要选用对应的spring-tool-suite进行安装&#xff0c;这点笔者浪费了好长时间&#xff0c;以下为对应的版本。eclipse-kepler.4.3.1–>springsource-tool-suite…

湖南工程学院计算机网络考试,湖南工程学院 计算机网络期末试卷试题

湖南工程学院 计算机网络期末试卷试题湖南工程学院 计算机网络 期末试题(计算机10级&#xff0c;90%的题目)1 从逻辑功能上看,计算机网络可分为哪两个子网?答&#xff1a;通信子网和资源子网 2 数据链路层的最基本功能答&#xff1a;数据链路层的最基本的功能是向该层用户提供…

C#设计模式(11)——外观模式(Facade Pattern)

一、引言 在软件开发过程中&#xff0c;客户端程序经常会与复杂系统的内部子系统进行耦合&#xff0c;从而导致客户端程序随着子系统的变化而变化&#xff0c;然而为了将复杂系统的内部子系统与客户端之间的依赖解耦&#xff0c;从而就有了外观模式&#xff0c;也称作 ”门面“…

OS X Mountain Lion上的多个Java版本

在Mountain Lion之前&#xff0c;Java被捆绑在OS X中。似乎在升级期间&#xff0c;我在计算机上安装的Java 6版本被删除了。 显然&#xff0c;在升级过程中卸载Java的原因是Java运行时存在的安全问题。通过这种方式&#xff0c;您不得不安装可解决此安全问题的最新版本。 所以我…

Oracle锁机制的总结【转】

最近在研究Oracle锁机制的时候发现网上的资料鱼龙混杂将&#xff0c;很多将问题复杂化&#xff0c;让人感觉没有条理性。经过查询原始理论资料&#xff0c;总结如下&#xff1a; 在数据库理论中&#xff0c;我们知道。我们在执行并发访问数据库表时&#xff0c;如果没有任何一致…

2020暨阳学院园林计算机考研考场,【图片】2020考研,老学长教你如何规划!【计算机考研吧】_百度贴吧...

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼二、关键一步——院校选择我把各位同学的院校选择阶段分为以上几个阶段&#xff0c;因为考研这一年中&#xff0c;很多人的目标院校并不是固定不变的&#xff0c;而是随着不同阶段而改变的。学长我在大三下学期这一时间段内也多次更…

List Box 控件

1 //定义变量&#xff0c;并关联控件与变量。IDC_RecvData为控件ID&#xff0c;recvData为控件对应的变量名 2 CListBox recvData; 3 4 DDX_Control(pDX, IDC_RecvData, recvData); 5 6 //向List Box控件IDC_RecvData中添加一行数据 7 CString str&#xff1b; 8 recvData.Ad…

JavaOne 2012:向上,向上和向外:使用Akka扩展软件

在最后的社区主题演讲后&#xff0c;我前往希尔顿金门大桥3/4/5观看了维克多巴生 &#xff08; Viktor Klang &#xff09;的&#xff08; Typesafe &#xff09;“上&#xff0c;下&#xff0c;外&#xff1a;Akka”演讲。 巴生&#xff08;Klang&#xff09;是Akka的技术主管…

华北科技学院计算机期末考试,华北科技学院 专业计算机 考试专用

1不能应用修剪命令“trim”进行修剪的对象是(D、文字) 。2. 命令行(B.不能随意移动)3. 布尔运算中差集的热键为(A.SU)4. 定距等分点用( C.DIST)命令5. 标高是以( B.厘米) 为单位6. 在建筑平面图中用以指明朝向的是( B.指北针)7. A3图纸的尺寸是( c.420x297)8. 既可以绘制直线&a…