现今,用户都期待能够通过 Web 访问快速的动态访问应用。本 系列文章 向您展示如何使用 Reverse Ajax 技术来开发事件驱动的 Web 应用程序。反向 Ajax,第 1 部分:Comet 简介 介绍了 Reverse Ajax、轮询、流、Comet 和长轮询。在您了解了如何通过 HTTP 使用 Comet 之后,就会发现长轮询是可靠地实现 Reverse Ajax 的最佳方式,因为目前所有浏览器都提供了这方面的支持。反向 Ajax,第 2 部分:WebSockets 展示了如何使用 WebSocket 实现 Reverse Ajax。代码示例有助于说明 WebSocket、FlashSocket、服务器端的约束、请求范围内的服务和暂停历时长久的请求。
本文将深入研究如何在不同 Web 容器和 API 的 Web 应用程序(Servlet 3.0 和 Jetty Continuation)中使用 Comet 和 WebSocket。了解如何通过抽象库(如 Socket.IO)透明地使用 Comet 和 WebSocket。Socket.IO 使用功能检测来决定是否将通过 WebSocket、AJAX 长轮询或 Flash 等来创建连接。
您可以 下载本文使用的源代码。
在理想情况下,要最大限度地充分利用本文,则应该了解 JavaScript 和 Java。本文创建的示例是使用 Google Guice 构建的。Google Guice 是用 Java 编写的依赖项注入框架。要理解本文内容,则需要熟悉依赖项注入框架的概念,比如 Guice、Spring 或 Pico。
要运行本文中的示例,还需要使用最新版的 Maven 和 JDK (请参阅 参考资料)。
您在 反向 Ajax,第 1 部分:Comet 简介 中应该已经了解到,Comet(长轮询或流)要求服务器在潜在的长延迟后能够暂停、重启或完成一个请求。反向 Ajax,第 2 部分:WebSockets 描述了服务器需要如何使用非阻塞 I/O 特性来处理一些连接,以及它们如何仅使用线程为请求提供服务(每请求线程模型)。您应该还了解到,WebSocket 的使用取决于服务器,并非所有的服务器都支持 WebSocket。
这一节将向您展示如何在 Jetty、Tomcat 和 Grizzly Web 服务器上使用 Comet 和 WebSocket(如果可以)。本文所提供的 源代码 包含了一个在 Jetty 和 Tomcat 上运行的简单聊天 Web 应用程序样例。本章节还将讨论支持 API 的下列应用服务器:Jboss、Glassfish 和 WebSphere。
Jetty 是一个 Web 服务器,它支持 Java Servlet 规范 3.0、WebSocket 和其他的集成规范。Jetty 具有以下特征:
- 强大而又灵活
- 易于嵌入
- 支持虚拟主机、会话集群和一些可以轻易通过 Java 代码进行配置的特性
- 适用于 Google App Engine 的托管服务
核心的 Jetty 项目是由 Eclipse Foundation 管理。
自从版本 6 开始,Jetty 包含了一个异步 API,称为 Jetty Continuation,它可以充许暂停某个请求,稍后再重新开始该请求。表 1 显示了 Jetty 主要版本所支持的规范和 API 的图表。
表 1. Jetty 版本和支持
| 支持 | Jetty 6 | Jetty 7 | Jetty 8 |
|---|---|---|---|
| 非阻塞 I/O | X | X | X |
| Servlet 2.5 | X | X | X |
| Servlet 3.0 | X | X | |
| Jetty Continuation (Comet) | X | X | X |
| WebSocket | X | X |
要通过 Comet 实现 Reverse Ajax ,可以使用 Jetty 所提供的 Continuation API,如下所示 清单 1:
清单 1. 用于 Comet 的 Jetty Continuation API
// Pausing a request from a servlet's method (get, post, ...):
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
Continuation continuation = ContinuationSupport.getContinuation(req);
// optionally set a timeout to avoid suspending requests for too long
continuation.setTimeout(0);
// suspend the request
continuation.suspend();
// then hold a reference for future usage from another thread
continuations.offer(continuation);
}
// Then, from another thread which wants to send an event to the client:
while (!continuations.isEmpty()) {
Continuation continuation = continuations.poll();
HttpServletResponse response =
(HttpServletResponse) continuation.getServletResponse();
// write to the response
continuation.complete();
}
|
完整的 Web 应用程序可在本文所附的 源代码 中找到。Jetty Continuation 存放在 JAR 文件中。您必须将此 JAR 文件放在 Web 应用程序的 WEB-INF/lib 文件夹中,以便能够使用 Jetty 的 Comet 特性。Jetty Continuation 也可以在 Jetty 6、Jetty 7 和 Jetty 8 上使用。
从 Jetty 7 开始,您还可以使用 WebSocket 特性。将 Jetty 的 WebSocket JAR 文件放入 Web 应用程序的 WEB-INF/lib 文件夹中,以便获得访问 Jetty 的 WebSocket API 的访问权,如 清单 2 中所示:
清单 2. Jetty 的 WebSocket API
// Implement the doWebSocketConnect and returns an implementation of
// WebSocket:
public final class ReverseAjaxServlet extends WebSocketServlet {
@Override
protected WebSocket doWebSocketConnect(HttpServletRequest request,
String protocol) {
return [...]
}
}
// Sample implementation of WebSocket:
class Endpoint implements WebSocket {
Outbound outbound;
public void onConnect(Outbound outbound) {
this.outbound = outbound;
}
public void onMessage(byte opcode, String data) {
outbound.sendMessage("Echo: " + data);
if("close".equals(data))
outbound.disconnect();
}
public void onFragment(boolean more, byte opcode,
byte[] data, int offset, int length) {
}
public void onMessage(byte opcode, byte[] data,
int offset, int length) {
onMessage(opcode, new String(data, offset, length));
}
public void onDisconnect() {
outbound = null;
}
}
|
可下载 源代码 中的 jetty-websocket 文件夹提供了一个聊天示例,它演示了如何使用 Jetty 提供的 WebSocket API。
Tomcat 可能是最广为人知的 Web 服务器。人们使用它已经很多年了,并且它已作为 Web 容器集成到早期版本的 Jboss 应用服务器中。Tomcat 还可以用作 servlet 规范的参考实现。servlet API 2.5 开始停用 Tomcat,人们开始关注基于非阻塞 I/O(如 Jetty)的替代物。表 2 显示了 Tomcat 两个最新版本支持的规范和 API。
表 2. Tomcat 支持
| 支持 | Tomcat 6 | Tomcat 7 |
|---|---|---|
| 非阻塞 I/O | X | X |
| Servlet 2.5 | X | X |
| Servlet 3.0 | X | |
| Advanced I/O (Comet) | X | X |
| WebSocket |
如 表 2 中所示,Tomcat 并不支持 WebSocket;它使用一个与 Jetty Continuation 等效的对等物(叫 Advanced I/O)来支持 Comet。Advanced I/O 是一个包装 NIO 的低级包装器,比优秀的 API 更能促进 Comet 的使用。使用此 API 的应用程序示例相对贪乏,没有几个。清单 3 显示了在聊天 Web 应用程序中用于挂起请求和恢复使用请求的 servlet 示例。您可以在本文里的 源代码 中找到完整的 Web 应用程序。
清单 3. Comet 的 Tomcat API
public final class ChatServlet extends HttpServlet
implements CometProcessor {
private final BlockingQueue<CometEvent> events =
new LinkedBlockingQueue<CometEvent>();
public void event(CometEvent evt)
throws IOException, ServletException {
HttpServletRequest request = evt.getHttpServletRequest();
String user =
(String) request.getSession().getAttribute("user");
switch (evt.getEventType()) {
case BEGIN: {
if ("GET".equals(request.getMethod())) {
evt.setTimeout(Integer.MAX_VALUE);
events.offer(evt);
} else {
String message = request.getParameter("message");
if ("/disconnect".equals(message)) {
broadcast(user + " disconnected");
request.getSession().removeAttribute("user");
events.remove(evt);
} else if (message != null) {
broadcast("[" + user + "]" + message);
}
evt.close();
}
}
}
}
void broadcast(String message) throws IOException {
Queue<CometEvent> q = new LinkedList<CometEvent>();
events.drainTo(q);
while (!q.isEmpty()) {
CometEvent event = q.poll();
HttpServletResponse resp = event.getHttpServletResponse();
resp.setStatus(HttpServletResponse.SC_OK);
resp.setContentType("text/html");
resp.getWriter().write(message);
event.close();
}
}
}
|
在 Tomcat 里,异步 servlet 必须实现一个 CometProcessor。对于异步 servlet,Tomcat 并不调用标准 HTTP 方法(doGet 和 doPost 等)。相反,会向
event(CometdEvent) 方法发送一个事件。在请求到达时,该示例会查看是否为了挂起该请求而使用了一个
GET 方法;不必调用 evt.close() 。如果调用的是一个
POST 方法,则表示用户发送了一个消息,该消息将传播至其他 CometEvent,并且可以调用 evt.close() 来完成请求的传送。在用户端,广播会让所有的长轮询请求来完成消息发送,并且会立即发送另一个长轮询请求来接收下一个事件。
Grizzly 并不是一个 Web 容器,它更像是一个帮助开发人员构建可伸缩性应用程序的 NIO 框架。它发展为 Glassfish 项目的一部分,但也可以单独或嵌套使用它。Grizzly 提供了充当 HTTP/HTTPS 服务器的部件,还为 Bayeux Protocol、Servlet、HttpService OSGi 和 Comet 等提供部件。Grizzly 支持 WebSocket,并且可以在 Glassfish 中使用它来支持 Comet 和 WebSocket。
Glassfish(Oracle 的应用服务器)是 J2EE 6 规范的参考实现。Glassfish 是一个完整的套件(像 WebSphere 和 Jboss 一样),它用 Grizzly 来支持 NIO、WebSocket 和 Comet。它的模块架构(基于 OSGI)使得更改部件变得非常灵活。表 3 显示了 Glassfish 对 Comet 和 WebSocket 的支持。
表 3. Glassfish 支持
| 支持 | Glassfish 2 | Glassfish 3 |
|---|---|---|
| 非阻塞 I/O | X | X |
| Servlet 2.5 | X | X |
| Servlet 3.0 | X | |
| Comet | X | X |
| WebSocket | X |
Grizzly 的使用并不繁琐,可以在 Java 代码中嵌套使用或直接使用它。人们普遍将它用作一个框架,用它来支持可以嵌套在大型应用程序(如 Glassfish)中的 Comet 和 WebSocket,这提供了 Web 部署功能和 Servlet 规范 API。
查看 参考资料 中关于 Grizzly 或 Glassfish 中的 WebSocket 和 Comet 示例的链接。因为 Glassfish 使用了 Grizzly,所以两个示例都有效。WebSocket API 与Jetty 中的非常相似,但是 Comet API 更复杂一些。
Jboss 是构建于 Tomcat 之上的应用服务器。从版本 5 起,它就开始支持 Comet 和 NIO。Jboss 7 还在开发中,但下面的 表 4 中包含该版本。
表 4. Jboss 支持
| 支持 | Jboss 5 | Jboss 6 | Jboss 7 |
|---|---|---|---|
| 非阻塞 I/O | X | X | X |
| Servlet 2.5 | X | X | X |
| Servlet 3.0 | X | X | |
| Comet | X | X | X |
| WebSocket |
WebSphere 是一个 IBM 应用服务器。WebSphere V8(参阅 参考资料,阅读相关声明)添加了对 Servlet 3 API(包括 Comet 的标准化异步 API)的支持。
表 5. WebSphere 支持
| 支持 | WebSphere 8 |
|---|---|
| 非阻塞 I/O | X |
| Servlet 2.5 | X |
| Servlet 3.0 | X |
| Comet | X |
| WebSocket |
每个服务器都自带了用于 Comet 和 WebSocket 的本机 API 。正如您所猜测的,编写一个便携版的 Web 应用程序会非常困难。Servlet 3.0 Specification 包含挂起请求并稍后重新使用请求的其他方法,并充许所有支持 Servlet 3.0 Specification 的 Web 容器支持 Comet 长轮询请求。
Jetty 团队提供了一个名叫 Jetty Continuation 的库,该库独立于 Jetty 容器。Jetty Continuation 库可以智能地检测容器或规范是否可用。如果在 Jetty 服务器上运行,则会使用本机 Jetty API 。如果在支持 Servlet 3.0 规范的容器上运行,则会使用通用的 API。否则会使用不可伸缩的实现。
关于 WebSocket,Java 中没有相关的标准,因此,如果您想要使用 WebSocket,则需要在 Web 应用程序中使用容器供应商 API 。
表 6 概括了各种服务器支持的技术
表 6. 服务器支持的技术
| 容器 | Comet | WebSocket |
|---|---|---|
| Jetty 6 | Jetty Continuation | N/A |
| Jetty 7 | Servlet 3.0 Jetty Continuation | Native Jetty API |
| Jetty 8 | Servlet 3.0 Jetty Continuation | Native Jetty API |
| Tomcat 6 | Advanced I/O | N/A |
| Tomcat 7 | Servlet 3.0 Advanced I/O Jetty Continuation | N/A |
| Glassfish 2 | Native Grizzly API | N/A |
| Glassfish 3 | Servlet 3.0 本机 Grizzly API Jetty Continuations | 本机 Grizzly API |
| Jboss 5 | 本机 Jboss API | N/A |
| Jboss 6 | Servlet 3.0 本机 Jboss API Jetty Continuation | N/A |
| Jboss 7 | Servlet 3.0 本机 Jboss API Jetty Continuations | N/A |
| WebSphere 8 | Servlet 3.0 Jetty Continuation | N/A |
关于 WebSocket, 除了使用容器 API ,没有其他的明确方案。至于 Comet,支持 Servlet 3.0 Specification 的所有容器都支持 Comet。Jetty Continuation 的优势是它在所有的这些容器上都提供了对 Comet 的支持。因此,一些 Reverse Ajax 库(在 下一节 和 本 系列 文章中的下一篇文章中会讨论它)都在对其服务器端 API 使用 Jetty Continuation。
Jetty Continuation API 在本文的 Jetty 示例 中曾描述过。Servlet 3.0 Specification 在本系列 第 1 部分:Comet 简介 的两个 Comet 示例中使用和描述过。
考虑到所有主要的 API(Servlet 3.0 和 Jetty Continuation)、服务器端的所有本机支持以及在客户端实现 Reverse Ajax 的两种主要方法(Comet 和 WebSocket),编写您自己的 JavaScript 和 Java 代码以便将它们连接在一起会非常困难。您还必须考虑超时、连接故障、确认、排序和缓冲等因素。
本文的其余部分将向您介绍 Socket.IO。本 系列 的第 4 部分将探讨 Atmosphere 和 CometD。这三个库均为开源库,它们都支持在许多服务器上使用 Comet 和 WebSocket。
Socket.IO 是一个 JavaScript 客户端库,可提供一个与 WebSocket 类似的 API,用该 API 连接到远程服务器,以便异步发送和接收消息。通过提供通用 API,Socket.IO 可支持多种传输:WebSocket、Flash Sockets、长轮询、流、forever Iframes 和 JSONP 轮询。Socket.IO 检测浏览器功能并尝试选择可用的最佳传输。Socket.IO 库几乎与所有的浏览器(包括旧版浏览器,如 IE 5.5)以及移动浏览器都兼容。它还提供了心跳、超时、断开连接和错误处理等功能。
Socket.IO 网站(参阅 参考资料)详细描述了库的工作原理以及使用哪种浏览器和 Reverse Ajax 技术。基本上,Socket.IO 使用一种可以使客户端库与服务器端的端点通信的通信协议,以便能够读懂 Socket.IO 协议。Socket.IO 最初是为 Node JS 开发的,它使用一个 JavaScript 引擎来构建快速服务器。许多项目都支持其他语言,其中包括 Java。
清单 4 显示了一个在客户端使用 Socket.IO JavaScript 库的示例。Socket.IO 网站中包含一些文档和示例。
清单 4. Socket.IO 客户端库的使用
var socket = new io.Socket(document.domain, {
resource: 'chat'
});
socket.on('connect', function() {
// Socket.IO is connected
});
socket.on('disconnect', function(disconnectReason, errorMessage) {
// Socket.IO disconnected
});
socket.on('message', function(mtype, data, error) {
// The server sent an event
});
// Now that the handlers are defined, establish the connection:
socket.connect();
|
要使用 Socket.IO JavaScript 库,则需要一个称为 Socket.IO Java 的相应 Java 部件(参阅 参考资料)。该项目最初由 Apache Wave 团队创建,创建于推出 WebSocket 之前,可利用该项目为 Reverse Ajax 提供支持。Socket.IO Java 是 Ovea(一家专门从事事件驱动 Web 开发的公司)的分支,由 Ovea 维护,后来遭到遗弃。由于有多种传输方式,所以开发后端来支持 Socket.IO 客户端库非常复杂。本系列的第 4 部分将展示如何支持客户端库中的许多传输,这种支持并不是获得更好的可伸缩性和浏览器支持所必需的,因为有长轮询和 WebSocket 就已经足够。在 WebSocket 尚未发布的时候,Socket.IO 确实是一个不错的选择。
Socket.IO Java 使用 Jetty Continuation API 来挂起和重新开始使用请求。它使用本机 Jetty WebSockets API 来支持 WebSocket。您可以使用 Socket.IO Java 确定哪一个服务器将与 Web 应用程序协同工作。
下面的 清单 5 显示了一个如何在服务器上使用 Socket.IO 的示例。您必须定义一个扩展 SocketIOServlet 的 servlet ,并实现返回某种端点表示形式的方法。此 API 与 WebSocket API 非常相似。该 API 的优势在于它可在服务器端使用,独立于客户端所选择的传输方式。Socket.IO 将所有的传输类型转化为与服务器端的 API 相同。
清单 5. 聊天示例 servlet 中使用的 Socket.IO Java 库
public final class ChatServlet extends SocketIOServlet {
private final BlockingQueue<Endpoint> endpoints =
new LinkedBlockingQueue<Endpoint>();
@Override
protected SocketIOInbound doSocketIOConnect
(HttpServletRequest request) {
String user =
(String) request.getSession().getAttribute("user");
return user == null ? null : new Endpoint(this, user, request);
}
void broadcast(String data) {
for (Endpoint endpoint : endpoints) {
endpoint.send(data);
}
}
void add(Endpoint endpoint) {
endpoints.offer(endpoint);
}
void remove(Endpoint endpoint) {
endpoints.remove(endpoint);
}
}
|
清单 6 显示了如何返回端点。
清单 6. 在聊天示例 Endpoint 中使用的 Socket.IO Java 库
class Endpoint implements SocketIOInbound {
[...]
private SocketIOOutbound outbound;
[...]
@Override
public void onConnect(SocketIOOutbound outbound) {
this.outbound = outbound;
servlet.add(this);
servlet.broadcast(user + " connected");
}
@Override
public void onDisconnect(DisconnectReason reason,
String errorMessage) {
outbound = null;
request.getSession().removeAttribute("user");
servlet.remove(this);
servlet.broadcast(user + " disconnected");
}
@Override
public void onMessage(int messageType, String message) {
if ("/disconnect".equals(message)) {
outbound.close();
} else {
servlet.broadcast("[" + user + "] " + message);
}
}
void send(String data) {
try {
if (outbound != null
&& outbound.getConnectionState() == ConnectionState.CONNECTED) {
outbound.sendMessage(data);
}
} catch (IOException e) {
outbound.close();
}
}
}
|
Socket.IO 的完整示例包含在 socketio 文件夹内的 源代码 中。
所有 Web 容器都支持 Comet,并且几乎都支持 WebSocket。即使规范会导致几种不同的本机实现 ,您仍然可以使用 Comet 和 API(Servlet 3.0 或 Jetty Continuation)来开发 Web 应用程序。甚至,您还可以使用诸如 Socket.IO 之类的库来透明地使用 Comet 和 WebSocket。还有另两个库(Atmosphere 和 CometD)将在本 系列 的下一篇文章中讨论。这三个库提供了多浏览器支持、美妙的用户体验,以及错误处理、更易于使用的 API、超时以及重新连接带来的好处。
| 描述 | 名字 | 大小 | 下载方法 |
|---|---|---|---|
| 文章源代码 | reverse_ajaxpt3_source.zip | 21KB | HTTP |
学习
- 阅读其系列的其他文章:
-
JSR 315: Java Servlet 3.0
Specification 是 2.5 规范的升级版。
- 阅读 IBM WebSphere Application Server V8.0 release announcement。
- "Google AppEngine uses Jetty!" 描述了 Google 的 Jetty 定制。
- 阅读了解关于 Jetty
Continuations 和一些特性的更多信息。
- 查看使用 Grizzly 的 Glassfish WebSockets 示例。
- WebSphere Application Server:了解 IBM WebSphere 中的更多旗舰产品。
-
WebSphere 8(支持 Comet) 支持应用程序环境的智能管理,并帮助于快速交付丰富的用户体验。
-
Socket.IO 的目标是使得在每个浏览器和移动设备上实现实时应用程序成为可能,消除不同传输机制之间的差异。
- "现在就开始使用 HTML5 WebSockets" (Nettuts+):查看如何在 PHP 上运行 WebSocket 服务器,并了解如何构建客户端,以便通过 WebSocket 协议发送和接收消息。
- "WebSocket API"
(W3C,2011 年 7 月):该规范定义了一个 API,使 Web 页面能够使用 WebSocket 协议与远程主机进行双向通信。
- 阅读了解关于 Servlet 3.0 中的异步处理支持 的更多信息。
- Philip McCarthy 的博客提供了关于 Comet & Java:
Threaded Vs Nonblocking I/O 的更多信息。
-
The Rox Java NIO
Tutorial 收集了作者使用 Java NIO 库的经验以及扰乱 Internet 的几十种提示、技巧、建议和警告。
- 在 Wikipedia 上阅读关于以下各项的信息:
-
Exploring Reverse AJAX:一些 Reverse-Ajax 技巧的介绍。
- "Cross-domain communications with JSONP, Part 1: Combine JSONP and
jQuery to quickly build powerful mashups"(developerWorks,
2009 年 2 月):了解如何结合使用晦涩的交叉域调用技巧 (JSONP) 和灵活的 JavaScript 库 (jQuery) 快速构建强大的混搭。
- "用 Ext JS 构建 Ajax 应用程序"(developerWorks,2008 年 7 月):获得发布 Ext JS 之后出现的一些面向对象的 JavaScript 设计概念的概述,并展示如何使用 Ext JS 框架获得丰富的 Internet 应用程序 UI 元素。
- "JavaScript 框架比较"(developerWorks,2010 年 2 月):获得大幅提高 JavaScript 开发的框架的概述。
- "掌握 Ajax,第 2 部分:使用 JavaScript 和 Ajax 进行异步请求"(developerWorks,2006 年 1 月):学习如何使用 Ajax 和 XMLHttpRequest 对象创建不会让用户等待服务器响应的请求/响应模型。
- "开发移动 Web Ajax 应用"(developerWorks,2010 年 3 月):了解如何使用 Ajax 构建交叉浏览器智能手机的 Web 应用程序。
- "在应用程序中使用 Ajax 的时机"(developerWorks,2008 年 2 月):了解如何使用 Ajax 改善您的网站,同时避免糟糕的用户体验。
- "改善 Web 2.0 应用程序的性能"(developerWorks,2009 年 12 月):研究不同的浏览器端缓存机制。
- "Introducing
JSON" (JSON.org):获得 JSON 句法的介绍。
-
developerWorks 中国网站 Web 开发专区:寻找介绍各种基于 Web 的解决方案的文章。
- developerWorks 技术活动和网络广播:随时关注 developerWorks 技术活动和网络广播。
获得产品和技术
-
Jetty:获得 Jetty、Web 服务器和 javax.servlet 容器,此外,提供对 WebSockets 的支持。
- Apache Tomcat
Advanced I/O documentation:获得有价值的链接、用户指南、参考和 Apache Tomcat Development 说明。
-
Grizzly NIO 框架:帮助您充分利用 Java NIO API 的优势。
-
Grizzly Comet
例子:了解在重新构建新的应用程序之前需要对现有应用程序进行的修改。
-
Glassfish 应用服务器:获得主要的 GlassFish Server 开源版本。
-
Socket.IO Java:获得原项目和最新的 Ovea 派生产品。
- Apache Maven:获得 Maven,这是一个软件项目管理和理解工具。
-
Java Development Kit, Version 6:获得 Java Platform, Standard Edition (Java SE),它使您能够在桌面和服务器以及当今充满挑战的嵌入环境中开发和部署 Java 应用程序。
- 免费试用 IBM 软件。下载试用版本,登录在线试用版本,在沙箱环境中使用产品,或是通过云来访问它。有超过 100 种 IBM 产品试用版可供您选择。
讨论

Mathieu Carbou 是 Ovea 公司的一名 Java Web 架构师和顾问,他提供服务和开发解决方案。他是几个开源项目的参与者和领导者、演讲人和蒙特利尔 Java 用户组的领导者。 Mathieu 具有很强的代码设计和最佳实践背景,是从客户端到后端事件驱动的 Web 开发方面的专家。他专注于为可高度扩展的 Web 应用程序提供事件驱动的消息传递解决方案。 请访问他的 博客。