spring观察者模式_Spring事件的观察者模式

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

spring观察者模式

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

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

相关文章

Lombok,自动值和不可变项

我喜欢布兰登&#xff08;Brandon &#xff09;在博客文章中比较Project Lombok &#xff0c; AutoValue和Immutables的建议 &#xff0c;而这篇文章试图做到这一点。 我已经简要概述了Project Lombok &#xff0c; AutoValue和Immutables &#xff0c;但是这篇文章有所不同&am…

linux对于zombie的处理

(Linux基础)[僵尸进程处理] 今天在服务器上推送项目的时候&#xff0c;突然发现很卡。就用top查看了一下&#xff0c;果然此事不简单啊。 top - 10:39:16 up 20 days, 23:11, 2 users, load average: 1.13, 1.09, 1.03 Tasks: 204 total, 2 running, 196 sleeping, 1 sto…

POJ - 1847 Tram(dijkstra)

题意&#xff1a;有向图有N个点&#xff0c;当电车进入交叉口&#xff08;某点&#xff09;时&#xff0c;它只能在开关指向的方向离开。 如果驾驶员想要采取其他方式&#xff0c;他/她必须手动更换开关。当驾驶员从路口A驶向路口B时&#xff0c;他/她尝试选择将他/她不得不手动…

用interrupt()中断Java线程

Javathread 最近在学习Java线程相关的东西&#xff0c;和大家分享一下&#xff0c;有错误之处欢迎大家指正&#xff0e; 假如我们有一个任务如下&#xff0c;交给一个Java线程来执行&#xff0c;如何才能保证调用interrupt()来中断它呢&#xff1f; Java代码 class ATask imple…

activemq和jms_保证主题,JMS规范和ActiveMQ的消息传递

activemq和jms最近&#xff0c;一位客户要求我仔细研究ActiveMQ的“持久”消息的实现&#xff0c;它如何应用于主题以及在存在非持久订户的故障转移方案中会发生什么。 我已经了解到&#xff0c;JMS语义规定&#xff0c;即使面对消息代理提供程序故障&#xff0c;也只能保证主题…

JAVA分代收集机制详解

Java堆中是JVM管理的最大一块内存空间。主要存放对象实例。在JAVA中堆被分为两块区域&#xff1a;新生代&#xff08;young&#xff09;、老年代&#xff08;old&#xff09;。堆大小新生代老年代&#xff1b;&#xff08;新生代占堆空间的1/3、老年代占堆空间2/3&#xff09;新…

FizzBu​​zz Kata与Java流

在柔道练习仅几周之后&#xff0c;我的儿子感到无聊。 他抱怨说自己没有学任何东西&#xff0c;因为他一遍又一遍地做着同样的事情。 混淆学习和做新事物的不仅仅是幼儿。 例如&#xff0c;有多少软件开发人员通过执行kata或参加dojos来进行刻意练习的麻烦&#xff1f; 重复您…

高可用架构

转载于:https://www.cnblogs.com/138026310/p/9088341.html

vc6.0快捷键

2010-09-14 17:46 F1 显示帮助,如果光标停在代码的某个字符上,显示MSDN中相应的帮助内容&#xff08;需要安装MSDN才能使用&#xff09; F2 书签功能: CtrlF2 --在某行设置一个书签(再按一次是取消) F2 --跳到下一个书签位置 ShiftF2 --跳到上一个书签位置 CtrlShiftF2 --删除…

ES6 各浏览器支持情况

http://kangax.github.io/compat-table/es6/转载于:https://www.cnblogs.com/likwin/p/9091008.html

MFC删除类的小窍门

VC 并没有提供删除一个类的简洁方法&#xff0c;我们需要手工删除&#xff0c;但过程并不复杂。例如&#xff0c;我们有一个 CMyButton 的类&#xff0c;对应的文件为 MyButton.h 和 MyButton.cpp &#xff0c;我们先到工程目录中删除这两个文件&#xff0c;此时该类信息自动从…

ios plist 国际化_Java与iOS对话:Java对象与Apple plist序列化

ios plist 国际化我很高兴地宣布我的第一个开源项目java-plist-serializer可以帮助您将Java&#xff08;尤其是基于Spring的应用程序&#xff09;与iOS应用程序集成在一起。 背景 我正在将Java webapp作为后端并且客户端是iOS设备的项目。 最近&#xff0c;我收到了创建Web服务…

vtk环境搭建(windowsXP/win7,vtk6.0.0+cmake2.8+vs2010)

1. 安装vs2010&#xff08;默认方式&#xff09; 2. 安装cmake2.8&#xff08;默认方式&#xff09; 3. 新建文件夹作为vtk文件根目录&#xff08;例如"E:\vtk6.0"&#xff09;&#xff0c;解压vtk-6.0.0.zip到根目录&#xff0c;将VTK6.0.0改名为vtk&#xff1b;解…

P1993 小K的农场 (差分约束)

题目描述 小K在MC里面建立很多很多的农场&#xff0c;总共n个&#xff0c;以至于他自己都忘记了每个农场中种植作物的具体数量了&#xff0c;他只记得一些含糊的信息&#xff08;共m个&#xff09;&#xff0c;以下列三种形式描述&#xff1a; 农场a比农场b至少多种植了c个单位…

将Quartz与Spring集成

在Java应用程序中调度作业时&#xff0c;Quartz是第一个考虑的工具。 Quartz是由最流行的RDBMS支持的作业调度程序。 这真的很方便&#xff0c;并且很容易与spring集成。 为了创建石英模式&#xff0c;您必须下载石英发行版并解压缩位于crystal-2.2.3 / docs / dbTables /中的…

linux下md5sum的使用

在linux或Unix上&#xff0c;md5sum是用来计算和校验文件报文摘要的工具程序。一般来说&#xff0c;安装了Linux后&#xff0c;就会有md5sum这个工具&#xff0c;直接在命令行终端直接运行。1、使用md5sum来产生指纹&#xff08;报文摘要&#xff09;命令如下&#xff1a;md5su…

深入理解Python中的元类(metaclass)

注&#xff1a;本文原稿来自stackoverflow&#xff0c;原文链接&#xff0c;目前已收获5k高赞。 一、类也是对象 在理解元类之前&#xff0c;你需要先掌握Python中的类。Python中类的概念借鉴于Smalltalk&#xff0c;这显得有些奇特。在大多数编程语言中&#xff0c;类就是一组…

6个步骤卸载wine

今天在ubuntu下装了个wine&#xff0c;感觉界面很难看&#xff0c;跟ubuntu风格不协调。所以我把它卸载了。 根据网上找的资料&#xff0c;我是按如下步骤卸载&#xff1a; 1.终端运行sudo apt-get remove wine&#xff0c;运行发现系统还有wine的图标残留&#xff0c;于是 2…

OpenStack基础知识-virtualenv工具详解

1、virtualenv介绍 virtualenv通过创建一个单独的虚拟化python运行环境&#xff0c;将我们所需的依赖安装进去&#xff0c;不同项目之间相互不干扰&#xff0c;从而解决不同的项目之间依赖不同&#xff0c;造成的冲突问题 2、安装virtualenv 通过pip命令&#xff0c;安装virtua…

java中的五种排序方法_用Java排序的五种有用方法

java中的五种排序方法Java排序快速概述&#xff1a; 正常的列表&#xff1a; private static List VEGETABLES Arrays.asList("apple", "cocumbers", "blackberry");Collections.sort(VEGETABLES);output: apple, blackberry, cocumbers反向排…