`

反向 Ajax,第 5 部分: 事件驱动的 Web 开发

阅读更多

简介

本 系列 文章向您展示如何使用反向 Ajax 技术开发事件驱动的 Web 程序。第 1 部分 介绍了反向 Ajax、轮询、流、Comet 和长轮询。第 2 部分 介绍了如何使用 WebSocket,还讨论了使用 Comet 和 WebSocket 的 Web 服务器的限制。第 3 部分 探讨了当您需要支持多个服务器或提供一个用户可以自己的服务器上部署的独立 Web 应用程序时,您实现自己的 Comet 或 WebSocket 通信系统的过程中会遇到的一些困难。第 3 部分还讨论了 Socket.IO。第 4 部分 介绍了 Atmosphere 和 CometD,它们是用于 Java 服务器的最有名的开放源码反向 Ajax 库。

此前,您已经了解了如何通过事件创建组件。在本系列最后一部分中,会应用到事件驱动开发原则,并构建一个事件驱动的 Web 应用程序示例。

您可以下载本文使用的 源代码

先决条件

在理想的情况下,如果想最大限度地利用本文,您应该了解 JavaScript 和 Java。要运行本文中的示例,则需要使用最新版的 Maven 和 JDK(参阅 参考资料)。

 

术语

您可能熟悉事件驱动架构 (EDA)、EventBus 系统、消息传递系统、复杂事件处理 (CEP) 以及通道。这些术语和概念已存在多年。随着技术越来越成熟,您可能会更多地听到它们。本节将简要解释这些概念。

事件
系统中发生的事情。事件通常拥有一些属性,比如发生日期(时间戳)、源或位置(我们单击的组件)以及一些事件描述数据。根据不同的系统,事件还可以拥有其他属性。
事件处理架构 (EDA)
也称为基于事件编程,这是一种架构设计模式,在这种模式中,应用程序包含一些组件,组件通过收发事件进行通信和执行操作。Java Swing 图形用户界面 (GUI) 就是一个 EDA 示例。每个 Swing 组件都可以执行监听事件、做出反应、发送其他事件等操作。EDA 包括几个组成部分:事件生成者、事件使用者、事件以及处理软件。
  • 事件生成者:该组件用于发出事件。在本文的示例中,一个表单提交按钮就是一个事件生成者。
  • 事件使用者:该组件用于监听特定事件。例如,在表单提交示例中,浏览器将监听表单提交按钮上的单击事件,以便向服务器发送表单数据。
  • 事件处理软件:这是事件生成者发布事件和事件使用者注册自己以接收事件的系统内核。根据不同的软件,处理过程可能很简单(只是将生成的事件转发到使用者),也可能很复杂(比如 CEP)。在使用 CEP 时,该软件支持各种处理方式,比如事件汇总、过滤和转换。

    Esper 就是这样一个软件。事件处理软件不仅可以是独立运行的应用程序,还可以是应用程序中集成的库。

消息传递系统
一种事件驱动应用程序,其中,事件生成者将消息发布到通道,事件使用者订阅通道。事件生成者和使用者之间没有链接,完全独立。在这种事件驱动应用程序中,通常使用术语消息,而不是事件
通道
消息传递系统中的事件的一种归类方法。通道表示事件生成者希望事件发送到的目标位置。例如,在一个聊天室应用程序中,通道可能是 /chatapplication/chatrooms/asdrt678。这个通道将标识一个聊天室,事件生成者可以在其中发送消息,图形组件可以订阅该聊天室,以显示新到达的消息。

某些消息传递系统提供两种通道:队列和主题。

  • 队列:在将消息发送到队列时,只有一个事件使用者能够接收并处理它。其他使用者看不到它。队列可以是持久性的,以保障消息交付。最好的队列示例可能是一个邮件请求。在用户进行注册的时候,Web 应用程序会将一条消息发布给队列 /myapp/mail/user-registration。可能有几个邮件应用程序订阅该队列。即使没有,消息也不会丢失。
  • 主题:在将消息传送到主题时,每个订阅者都会接收到相关消息。主题通常不是持久性的。针对监控软件的主题的一个是 /event/system/cpu/usage,其中一个生成者会定期发送 CPU 的使用情况。另一方面,可能有很多订阅者,也可能完全没有订阅者,这主要取决于订阅者的兴趣。
发布/订阅
事件驱动解决方案实现了 “发布/订阅” 模式。事件生成者在处理软件中发布事件,事件使用者通过订阅来接收事件。事件使用者的订阅方式取决于软件。在消息传递应用程序中,事件使用者可以订阅通道(例如,也可以在事件类型上应用过滤规则)。在使用 CEP(比如 Esper)时,可以通过一个 SQL 类请求来实现订阅,从而定义您感兴趣的事件。
 

为何使用事件驱动解决方案?

在传统通信方案中,如果系统 A 需要系统 B 中的信息,它会向系统 B 发送一个请求。系统 B 将处理请求,而系统 A 会等待响应。处理完成后,会将响应发送回系统 A。在同步 通信模式下,资源使用效率比较低,这是因为等待响应时会浪费处理时间。

异步 模式下,系统 A 将订阅它想从系统 B 中获取的信息。然后,系统 A 可以向系统 B 发送一个通知,也可以立即返回信息,与此同时,系统 A 可以处理其他事务。这个步骤是可选的。在事件驱动应用程序中,通常不必请求其他系统发送事件,因为您不知道这些事件是什么。在系统 B 发布响应之后,系统 A 会立即收到该响应。

事件驱动架构的一个好处是它允许实现更好的可伸缩性。可伸缩性 是系统在适应需求、量和强度方面的变化的情况下仍能实现目标的能力。通过消除暂停时间,使得事件驱动架构拥有更好的性能和更高的处理比率。

另一个好处在于应用程序开发和维护。在使用事件驱动解决方案时,每个应用程序组件都可以去除耦合,完全独立。

由于通信延迟减少,事件驱动解决方案能够在更短地时间内进行响应。

 

将事件驱动解决方案应用于 Web

Web 框架过去通常依赖传统 “请求-响应” 模式,该模式会导致页面刷新。随着 Ajax、Reverse Ajax 以及 CometD 和 Atmosphere 等强大框架的出现,现在可以将事件驱动架构的概念轻松应用于 Web,获得去耦合、可伸缩性和反应性 (reactivity) 等好处。

在客户端

事件驱动架构可用于客户端的 GUI 开发。您可以拥有充当容器的单个 Web 页,而不是创建传统的 Web 页面。每个元素(页面的每个部分)都可以进行隔离。您可以在 Web 上拥有一个 Java Swing GUI,就像包含小工具的 Google 页面(参见 参考资料 中的链接)。

您还需要一个事件总线。例如,您可以开发一个 JavaScript 事件总线,允许订阅每个页面元素并将它发布到通道。还可以对事件进行同步,以便在收到两个或更多事件后触发操作。事件总线可用于页面中的本地事件,您也可以通过 CometD 或 Socket.IO 使用插件来支持远程事件。

在服务器端

在服务器端上,需要设置一个反向 Ajax 框架来支持事件驱动架构。在本系列前面的文章中介绍过的框架中,只有 CometD 拥有事件驱动方案。要使用其他框架,则需要添加自定义支持,这不太容易。您还可以添加第三方消息传递系统,比如 JMS(例如 Apache ActiveMQ)或一个 CEP(例如 Esper)。Redis 是一个更简单的解决方案,它支持基本 “发布/订阅” 功能。

本系列的主题是事件驱动 Web 和反向 Ajax,因此我们将只关注客户端部分,不会建立一个复杂的消息传递系统。

 

事件驱动 Web 示例

本文将创建的示例是一个聊天室 Web 应用程序,它有一个用户面板,其中包含已连接用户的列表。您的用户名为粗体,活动用户(20 秒后仍然活动的用户)显示为绿色,20 秒后不活动的用户显示为橙色。如果一个用户连接或断开连接,列表就会刷新。

出于安全考虑,web.xml 文件中配置了两分钟的会话超时。如果两分钟后仍处于不活动状态,系统会弹出一个窗口,将您重定向到登录页面。

只要您没有进行会话或还没有连接,就会被重定向到登录页面。登录页面要求输入用户名,检查您是否可以登录到聊天室。

登录后,您就可以向聊天室中的所有用户发送消息。您还会看到一个控制台,其中记录了收到的所有事件。

这个 Web 应用程序是事件驱动的。您可以使用上面的信息轻松地定义以下几个事件:

  • 用户连接
  • 用户断开连接
  • 会话过期
  • 收到一条聊天消息
  • 安全过滤器在您未登录时阻止了一个请求
  • 用户变为不活动
  • 用户变为活动
  • 与 UI 协调相关的其他所有事件

有些事件只是 Web 应用程序的本地事件。它们通过一个本地总线进行标识,如 清单 1 中所示:

清单 1. 总线设置
bus = { 
 
    local: new EventBus({ 
        name: 'EventBus Local' 
    }), 
 
    remote: EventBus.cometd({ 
        name: 'EventBus Remote', 
        logLevel: 'warn', 
        url: document.location.href.substring(0, 
            document.location.href.length - 
            document.location.pathname.length) + '/async', 
        onConnect: function() { 
            bus.local.topic('/event/bus/remote/connected').publish(); 
        }, 
        onDisconnect: function() { 
            bus.local.topic('/event/bus/remote/disconnected').publish(); 
        } 
    }) 
 
};

另一些事件是远程的,这意味着它们需要通过一个反向 Ajax 系统(比如 CometD)在所有客户端之间发布。图 1 展示了一个示例应用程序。

图 1. 示例应用程序

示例应用程序屏幕快照

您可以 下载 示例应用程序。许多类都是适用于安全管理或会话和用户管理的管道类 (plumping class)。本文展示了最重要的代码部分,但建议您下载并运行示例应用程序,以便深入考察其运行方式。

这个 Web 应用程序包含不同的组件:聊天室、用户列表和控制台。每个组件都是独立的,移除一个组件不会影响其他组件。

为了设置事件驱动系统(本地和远程),本示例使用了 Ovea 的 EventBus 系统。它提供一个本地事件总线、一个 CometD 用来获取远程事件的网桥以及一种协调事件(以便在完成几个事件后触发相关操作)的方法。如果愿意,您完全可以使用另一种系统替代它。示例设置使用了 JavaScript,如 清单 1 中所示。

总线设置好之后,应用程序和组件就成为基于事件的应用程序和组件了。在本例中,对 IDLE 检测系统进行了设置,如 清单 2 中所示:

清单 2. IDLE 检测系统
bus.local.topic('/event/dom/loaded').subscribe(function() { 
    $.idleTimer(20000); 
    $(document).bind('idle.idleTimer', function() { 
        bus.local.topic('/event/idle').publish('inactive'); 
    }); 
    $(document).bind('active.idleTimer', function() { 
        bus.local.topic('/event/idle').publish('active'); 
    }); 
})

使用 清单 2 中的代码,IDLE 系统会在检测到活动时发送事件。这个代码可以用于任何需要 IDLE 系统的应用程序。在本例中,您需要在用户活动事件中转换它。该系统也使用了 JavaScript 实现,如 清单 3 中所示:

清单 3. 用户活动管理
bus.local.topic('/event/idle').subscribe(function(status) { 
    bus.remote.topic('/event/user/status/changed').publish({ 
        status: status == 'active' ? 'online' : 'away' 
    }); 
}); 
 
bus.remote.topic('/event/user/status/changed').subscribe(function(evt) { 
    if(evt.user != me.name) { 
        $('#users li').filter(function() { 
            return evt.user == $(this).data('user').name; 
        }).removeClass('online')
          .removeClass('away')
          .addClass(evt.status); 
    } 
});

第一个订阅从 IDLE 系统接收事件,将用户状态发送给服务器。另一个订阅从服务器接收用户状态事件。这样,只要用户状态变化,用户列表中的用户颜色就会变为绿色或橙色。

用户连接或断开连接时,系统会发送一个事件,如 清单 4 中所示:

清单 4. 用户列表管理
bus.remote.topic('/event/user/connected').subscribe(function(user) { 
    $('#users ul').append(row(user)); 
}); 
 
bus.remote.topic('/event/user/disconnected').subscribe(function(evt) { 
    $('#users li').filter(function() { 
        return evt.user == $(this).data('user').name; 
    }).remove(); 
});

这个应用程序代码比较简单,消除了耦合并且被隔离。通过重用大量 Ovea 技术,您可以快速创建事件驱动的 Web 应用程序。但是,无需如此,因为另一个系统可以取代它的位置。这个示例只需一天时间即可开发出来,半数代码都是管道代码,包括内容如下:

  • Maven,用于构建项目
  • 安全特性(登录、退出和会话超时)
  • 使用 Jersey 的 RES 服务
分享到:
评论

相关推荐

    基于反向Ajax技术的终端驱动Web服务.pdf

    【反向Ajax技术】是Web开发中的一个重要概念,它是在传统Ajax技术的基础上发展起来的,主要解决了传统Ajax技术无法实现实时性较高场景的问题。传统Ajax技术是客户端发起请求,服务器响应并返回数据,而反向Ajax则是...

    HtmlSocket:开源反向ajax框架

    在Web开发中,传统的Ajax技术主要是从客户端向服务器发送请求并获取数据,而反向Ajax(也称为Comet技术)则允许服务器主动推送数据到客户端,极大地提高了实时性,尤其适用于实时聊天、股票行情、在线游戏等应用场景...

    Comet4j demo

    3. **事件驱动**:Comet4j基于事件驱动模型,允许开发者注册监听器来处理服务器推送的事件,简化了编程模型。 4. **兼容性**:Comet4j兼容多种Web容器,如Tomcat、Jetty等,使得开发者可以方便地将其集成到现有的...

    Dwr 官方Reverse Ajax Demo

    Reverse Ajax(反向Ajax)是指服务器主动向客户端推送数据,而不是等待客户端发起请求。这种技术在实时更新、聊天应用、股票报价等场景中非常有用。DWR通过建立长连接或者轮询机制实现Reverse Ajax。 1. **Long ...

    Servlet3.0

    5. **WebSocket支持**: 虽然不是Servlet 3.0的一部分,但WebSocket协议的API在Servlet 3.1中被引入,提供了低延迟、双向通信的网络连接,进一步增强了Web应用的交互性。 综上所述,Servlet 3.0的异步支持和反向Ajax...

    Python 06-web前端.zip

    5. **Ajax技术**:Python可以通过XMLHttpRequest对象实现Ajax异步通信,更新部分网页内容,无需刷新整个页面,提高用户体验。 6. **RESTful API设计**:Python后端常通过设计RESTful API与前端进行数据交互,遵循...

    DWR框架体验(实现基于ajax的无刷新效果)

    这种方式被称为反向Ajax,使得Web应用能够实现类似桌面应用的实时交互效果。 2. **自动暴露 (Auto-Exposure)**: DWR 自动将Java对象和方法暴露给JavaScript,简化了开发过程。开发者只需在Java类上添加注解,DWR就...

    dwr服务器推技术实例

    在DWR中,我们可以通过创建一个反向AJAX的通道(Reverse Ajax Channel),并注册监听器,当服务器有新的数据时,可以立即通知到客户端,更新页面内容。这极大地提高了用户体验,因为用户不需要频繁刷新页面就能获取...

    Java Web登录Demo(SSM+Ajax)

    demo主要运用SSM框架完成用户的登录功能;demo集成了MyBatis反向生成工程;demo的后台运用了spring的自动注入、springMVC的请求驱动、MyBatis面向接口数据库编程技术;JSP前台和后台交互的响应模式;

    dwr扥一个DEMO

    5. **事件驱动编程**:DWR允许在JavaScript中注册服务器端事件,当服务器端发生特定事件时,客户端可以得到通知。 6. **调试工具**:DWR提供了一个内置的调试器,可以帮助开发者在浏览器中查看和调试远程调用。 7....

    Springside之开发bookstore心得

    - **订单确认与通知**:用户提交订单后,系统会使用DWR(Direct Web Remoting)实现反向Ajax技术向管理员推送新订单通知;同时利用JMS(Java消息服务)实现异步发送邮件给用户确认订单详情。 #### 后台管理系统 - ...

    Practical DWR 2 Projects(英文)

    1. **反向Ajax(Reverse Ajax)**:DWR实现了服务器向浏览器推送数据的能力,使得Web应用可以实现类似桌面应用的即时反馈效果。 2. **自动类型转换**:DWR能够自动处理Java对象与JavaScript对象之间的类型转换,...

    PHP 开源AJAX框架14种

    在Web开发领域,AJAX(Asynchronous JavaScript and XML)技术因其可以提升用户体验,实现页面无刷新更新而受到广泛应用。PHP作为服务器端的强大脚本语言,与AJAX相结合,可以创建出高效、动态的网页应用。下面我们...

    dwr应用实例

    3. **反向AJAX**:DWR中的反向AJAX指的是服务器主动推送数据到客户端,而不仅仅是响应客户端的请求。 ### 二、DWR的工作原理 1. **配置**:DWR需要在服务器端配置,通常在`dwr.xml`文件中定义允许访问的Java类和...

    comet4j开发指南

    1. **异步处理**:Comet4J支持非阻塞I/O,通过事件驱动模型提高服务器处理能力,避免了线程池的过度消耗。 2. **高并发**:通过高效的连接管理和数据缓存策略,Comet4J能处理大量并发连接,确保大规模应用的稳定...

    JavaEE求职简历-姓名-JAVA开发工程师.docx

    3. **Java Web应用开发**:熟悉listener、EL(Expression Language)、JSTL(JavaServer Pages Standard Tag Library)和Filter等技术,这些都是构建动态Web应用的重要组成部分,能处理请求、响应、页面逻辑和数据...

    mvc 移动端开发

    5. **Events**:事件系统允许不同组件之间通过事件进行通信,减少耦合。 在实际开发中,可能会涉及到以下知识点: - 使用`fetch`或`Backbone.sync`进行异步数据请求,如AJAX,与服务器交换数据。 - 使用模板引擎...

    Nodeclub 是使用 Node.js 和 MongoDB 开发的社区系统.zip

    5. **Express 框架**:Node.js 中最常用的 Web 开发框架之一,提供了一套简洁的 API 来创建 Web 应用。Nodeclub 可能使用 Express 定义路由、处理 HTTP 请求和响应。 **MongoDB 知识点:** 1. **文档型数据库**:...

Global site tag (gtag.js) - Google Analytics