JSR 356, Java API for WebSocket

学习如何整合WebSocket到你的应用中。

对于许多基于Web的客户服务端应用,以前的HTTP请求-响应模型有它的限制。信息必须要在响应时被从服务端传送到客户端,不仅仅是请求。

过去有许多技巧可以用于解决这个问题,如长连接和Comet。然而,需要一个标准的,双向的,全双工的在客户和服务器之间的通道的需求在持续增长。

2011年,IETF将WebSocket协议标准化为RFC6455。从那开始,主要的web浏览器已经实现了支持WebSocket协议的客户端API。同时,许多实现WebSocket协议的Java库已经被开发出来。

WebSocket协议利用了HTTP上行技术来上行一个HTTP连接到一个WebSocket,一旦上行到WebSocket,此连接即可在两个方向发送消息(数据帧),也即工作于全双工模式。不需要Header或cookie,这样就大大降低了所需的带宽,一般情况下,WebSocket主要用于周期性的发送小消息(如几kb)。附加的header通常会使开销大于负荷。

JSR 356

JSR 356,Java WebSocket API,规定了当Java开发者想要将WebSockets整合到它们的应用中时可以使用的API——无论服务端还是客户端。每一个宣称符合JSR 356的WebSocket协议的实现都必须实现这些API,因此,开发者可以写他们的WebSocket应用而无需管底层的WebSocket实现是什么。这是一个巨大的优点,它可以避免被绑定到一个固定的供应商,以便有更多的选择、自由的库和应用服务器。

JSR 356是即将到来的J2EE 7标准的一部分。因此,所有兼容J2EE 7的应用服务器都将有一个遵循JSR 356标准的WebSocket协议实现。一旦建立,WebSocket客户和服务端节点将是对称的,因此,客户端API和服务器API的区别是最小的,JSR 356也定义了Java客户端API,它是Java EE 7所需的完整API的一个子集。

一个采用WebSockets的客户-服务端应用一般会包含一个服务端组件和一个或多个客户端组件,如图1所示:

 jsr

在这个例子中,服务器端应用采用Java进行编写,WebSocket协议细节由JSR 356实现,其包含在J2EE 7容器中。

一个JavaFX客户端可以依据任何兼容JSR 356的客户端实现来处理WebSocket特定的协议问题。其它客户端(如IOS客户端和HTML5客户端)可以使用其它兼容RFC 6455的非Java实现来与服务端应用交互。

编程模型

定义JSR 356的专家组想要支持对于J2EE开发者来说比较通用的模式和技术,因此,JSR 356使用了注解和注入。

一般来说,支持两种不同的编程模型:

  • 注解驱动,使用注解POJOs,开发者可以与WebSocket生命周期事件交互。
  • 接口驱动,开发者可以实现与生命周期事件交互的Endpoint接口及其方法。

生命周期事件

WebSocket交互的典型生命周期事件有:

  • 一个节点(客户端)通过发送一个HTTP握手请求初始化连接。
  • 另一个节点(服务端)通过一个握手响应进行回复。
  • 连接建立,从此刻起,此连接是完全对称的。
  • 两个节点相互发送与接收信息。
  • 其中一个节点关闭连接。

大多数的WebSocket声明周期事件可以被映射到Java方法,无论是注解驱动的方式还是接口驱动的方式都可。

注解驱动的方法

一个接受到来的WebSocket请求的endpoint可以是采用@ServerEndpoint注解的注解POJO,这个注解告诉容器被注解的类是一个WebSocket的endpoint,此注解必选的value属性指定WebSocket endpoint的路径。

考虑下面的代码片段:

 
 
  1. @ServerEndpoint("/hello")
  2. public class MyEndpoint { } 

这个代码将以相对路径hello发布一个endpoint。endpoint的路径中可以包含在后续方法调用中使用的路径参数,例如:/hello/{userid}是一个有效的路径,这里{userid}的值可以在生命周期方法调用中通过@PathParam注解得到。

在GlassFish中,如果你的应用部署在本地Web容器中,监听在8080端口,根上下文为mycontextroot,那么,此WebSocket可以通过使用ws://localhost:8080/mycontextroot/hello存取。

而初始化WebSocket连接的endpoint则是采用@ClientEndpoint注解的注解POJO。@ClientEndpoint与@ServerEndpoint主要的不同点在于@ClientEndpoint不接受路径值属性,因为它不监听到来的连接请求。

 
 
  1. @ClientEndpoint
  2. public class MyClientEndpoint {}

在Java中,采用注解驱动的POJO方法初始化WebSocket连接可以这么做:

 
 
  1. javax.websocket.WebSocketContainer container =
  2. javax.websocket.ContainerProvider.getWebSocketContainer();
  3.  
  4. container.conntectToServer(MyClientEndpoint.class,
  5. new URI("ws://localhost:8080/tictactoeserver/endpoint"));

今后,采用@ServerEndpoint或@ClientEndpoint注解的类将称为注解endpoints。

一旦一个WebSocket连接被建立,一个Session会被创建,并且在注解endpoint中用@OnOpen注解的方法将会被调用,这个方法包含了一些参数:

  • 一个java.websocket.Session参数,指定创建的Session
  • 一个EndpointConfig实例,它包含了endpoint的配置信息。
  • 一个或多个采用@PathParam注解的字符串参数,它们指向endpoint路径中的路径参数。

下面实现的方法将会打印出WebSocket打开时的session的标示符:

 
 
  1. @OnOpen
  2. public void myOnOpen (Session session) {
  3. System.out.println ("WebSocket opened: "+session.getId());
  4. }

只要WebSocket没被关闭,那么Session实例便是有效的。Session类中包含了一些有趣的方法用于帮助开发者获取更多有关此连接的信息。同时,Session还包含一个对特定应用数据的hook,它利用getUserProperties()方法返回一个Map<String,Object>对象。这样,开发者便可以利用在方法调用中共享的session及应用特定的信息产生Session实例。

当WebSocket endpoint接收到一条信息,使用@OnMessage注解的方法将会被调用,用@OnMessage注解的方法有以下的参数:

  • javax.websocket.Session参数
  • 一个或多个采用@PathParam进行注解的字符串参数,它们指向endpoint路径中的路径参数
  • 消息本身,可能的消息类型可以参照下面的内容。

当有一条文本消息从另一个节点发送过来时,消息的内容将会通过下面的代码片段打印出来:

 
 
  1. @OnMessage
  2. public void myOnMessage (String txt) {
  3. System.out.println ("WebSocket received message: "+txt);
  4. }

如果被@OnMessage注解的方法的返回类型不是void,WebSocket的实现会将返回值发送给另一个节点。下面的代码片段会将接收到的文本消息以大写的形式返回给发送方:

 
 
  1. @OnMessage
  2. public String myOnMessage (String txt) {
  3. return txt.toUpperCase();
  4. }

另一种通过WebSocket连接发送消息的方式如下:

 
 
  1. RemoteEndpoint.Basic other = session.getBasicRemote();
  2. other.sendText ("Hello, world");

在这个方法中,我们从可以获取生命周期回调方法(如使用@OnOpen注解的方法)的Session对象开始。Session对象的getBasicRemote()方法将会返回对等的另一个WebSocket节点,也即RemoteEndpoint,得到的RemoteEndpoint实例可用于发送文本或者其它类型的消息。

当WebSocket连接被关闭时,被@OnClose注解的方法将被调用,此方法的参数有:

  • javax.websocket.Session参数,必须注意:一旦WebSocket连接已经关闭,也即被@OnClose注解的方法已经返回,则此参数不能再使用。
  • javax.websocket.CloseReason参数,它描述了WebSocket关闭的原因,例如:正常关闭、协议错误、服务过载等等
  • 一个或多个使用@PathParam注解的字符串参数,它们指向endpoint路径中的路径参数

下面的代码片段会打印出WebSocket要关闭的原因:

 
 
  1. @OnClose
  2. public void myOnClose (CloseReason reason) {
  3. System.out.prinlnt ("Closing a WebSocket due to "+reason.getReasonPhrase());
  4. }

为了更加完整,另外还有一个生命周期注解:当有错误发生时,被@OnError注解的方法将会被调用。

未完待续……

原文出处:http://www.oracle.com/technetwork/articles/java/jsr356-1937161.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值