4. WebSocket

包含了Servlet stack,原生WebSocket交互,通过SockJS模拟,并且通过STOMP在WebSocket之上订阅、发布消息。

4.1 简介

不扯了,看到这个地方的都已经知道WebSocket是干啥的,用在啥地方。

4.2 WebSocket API

Spring框架提供了WebSocket的API,可以用来写处理WebSocket消息的client和server的程序。

4.2.1 WebSocketHandler

创建一个WebSocket服务器很简单,实现WebSockHandler接口就完事了。或者更具体点,继承TextWebSocketHandler或者BinaryWebSocketHandler:

import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.TextMessage;
public class MyHandler extends TextWebSocketHandler {
  @Override
  public void handleTextMessage(WebSocketSession session, TextMessage message) {
  // ...
  }
}

通过下面的java代码将上面的Handler配置到具体的URL上:

import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
  @Override
  public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
    registry.addHandler(myHandler(), "/myHandler");
  }
  @Bean
  public WebSocketHandler myHandler() {
    return new MyHandler();
  }
}

在SpringMVC应用里,上面的配置可以可以包含在DispatcherServlet的配置中。然而,Spring WebSocket可以独立于SpringMVC。通过WebSocketHttpRequestHandler可以把WebSocketHandler集成到其他的HTTP服务环境中。

4.2.2 WebSocket握手

自定义初始HTTP WebSocket握手请求的最简单的方法是通过HandShakeInterceptor,它提供了“before”和“after”握手方法。这些拦截器可以用来阻止握手或者让WebSocketSession得到一下属性。例如,有一个内置的拦截器,可以用来向WebSocket的session传递HTTP的session的属性。

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
  @Override
  public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
    registry.addHandler(new MyHandler(), "/myHandler")
    .addInterceptors(new HttpSessionHandshakeInterceptor());
  }
}

更高级的选项是继承DefaultHandshakeHandler,它执行WebSocket握手步骤,包括验证客户端来源,协商子协议等。如果应用程序需要配置自定义RequestUpgradeStrategy以适应WebSocket服务器引擎和尚不支持的版本,则应用程序可能还需要使用此选项(有关此主题的更多信息,请参阅部署)。

4.2.3 部署

Spring WebSocket API易于集成到Spring MVC应用程序中,其中DispatcherServlet同时提供HTTP WebSocket握手以及其他HTTP请求。 通过调用WebSocketHttpRequestHandler,也可以轻松地集成到其他HTTP处理场景中。 这很方便易懂。 但是,JSR-356 runtimes有些特殊注意事项。

Java WebSocket API(JSR-356)提供了两种部署机制。

  • 第一个涉及启动时的Servlet容器classpath扫描(Servlet 3功能);
  • 另一个是在Servlet容器初始化时使用的注册API。

这些机制都不能使用单个“前端控制器”进行所有HTTP处理 - 包括WebSocket握手和所有其他HTTP请求 - 例如Spring MVC的DispatcherServlet。

这是JSR-356的一个重要限制,Spring的WebSocket支持即使在JSR-356运行时运行时也能解决特定于服务器的RequestUpgradeStrategy问题。 Tomcat,Jetty,GlassFish,WebLogic,WebSphere和Undertow(以及WildFly)目前存在这样的策略。 (这段没看太明白,WEBSOCKET_SPEC-211可以解决这个问题)

第二个考虑因素是具有JSR-356支持的Servlet容器应该执行ServletContainerInitializer(SCI)扫描,这可能会减慢应用程序启动速度,在某些情况下会显着降低。 如果在升级到支持JSR-356的Servlet容器版本后观察到重大影响,则应该可以通过在web.xml中使用<absolute-ordering />元素来选择性地启用或禁用Web片段(和SCI扫描).

4.2.4 Server配置

每个底层WebSocket引擎都公开控制运行时特性的配置属性,例如消息缓冲区大小,空闲超时等。

对于Tomcat,WildFly和GlassFish,将ServletServerContainerFactoryBean添加到WebSocket Java配置中:

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer { @Bean
public ServletServerContainerFactoryBean createWebSocketContainer() {
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
container.setMaxTextMessageBufferSize(8192);
container.setMaxBinaryMessageBufferSize(8192);
return container;
}
}

对于client端,使用ContainerProvider.getWebSocketContainer()来配置。(XML中用WebSocketContainerFactoryBean)

4.2.5 Allowed origins

hmmm,暂时没啥用,用的时候网上一搜一大堆~~

4.3 SockJS方案

模拟器,在原生WebSocket API不能用的情况下,通过SockJS继续实现功能。

4.3.1 概要

就那回事吧,不写了。

4.3.2 启用SockJS

很简单,通过java代码即可:

@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
  registry.addHandler(myHandler(), "/myHandler").withSockJS();
}

在浏览器里,程序可以使用sockjs-client来搞事情。

4.3.3 IE8,9

跳过这节,现在用Ubuntu呢:)

4.3.4 心跳

SockJS需要服务器发送心跳信号来防止连接挂掉。Spring SockJS配置有个属性叫做heartbeatTime,可以用来自定义心跳频率。默认在没有通讯25秒之后跳。

Spring SockJS也支持配置一个TaskScheduler来调度心跳任务。

4.3.5 Client disconnects

客户端断开了,但是服务器不知道。得注意。

4.3.6 SockJS和CORS

这个暂时也用不上。

4.3.7 SockJS Client

可以提供测试。一个Java的SockJS的Client。

4.4 STOMP

WebSocket只定义了2种消息:Test和Binary,但是没定义它们的内容。这是和STOMP出现了,定义了消息的种类,格式和内容。

4.4.1 概述

客户端可以使用SEND或SUBSCRIBE命令发送或订阅消息以及“目标”标头,该标头描述消息的内容以及应由谁接收消息。这启用了一个简单的发布 - 订阅机制,可用于通过代理将消息发送到其他连接的客户端,或者向服务器发送消息以请求执行某些工作。

使用Spring的STOMP支持时,Spring WebSocket应用程序充当客户端的STOMP代理。消息被路由到@Controller消息处理方法或者路由到一个简单的内存代理,该代理跟踪订阅并向订阅用户广播消息。您还可以将Spring配置为使用专用的STOMP代理(例如RabbitMQ,ActiveMQ等)来实现消息的实际广播。在这种情况下,Spring维护与代理的TCP连接,向其中继消息,并将消息从其传递到连接的WebSocket客户端。因此,Spring Web应用程序可以依赖于基于HTTP的统一安全性,通用验证以及熟悉的编程模型消息处理工作。

这是订阅接收股票报价的客户的示例,服务器可以周期性地发出该报价。通过计划任务通过SimpMessagingTemplate将消息发送到代理:

SUBSCRIBE
id:sub-1
destination:/topic/price.stock.*
^@

以下是客户端发送交易请求的示例,服务器可以通过@MessageMapping方法处理该交易请求,稍后在执行后,向客户端广播交易确认消息和详细信息:

SEND
destination:/queue/trade
content-type:application/json
content-length:44 {"action":"BUY","ticker":"MMM","shares",44}^@

在STOMP规范中故意将目的地的含义保持不透明。 它可以是任何字符串,完全取决于STOMP服务器,以定义它们支持的目标语义和语法。 然而,很常见的是,目标是类似路径的字符串,其中“/ topic / ..”表示发布 - 订阅(一对多),“/ queue /”表示点对点(一对一) -one)消息交换。

使用MESSAGE来广播消息到所有客户端:

MESSAGE
message-id:nxahklf6-1
subscription:sub-1
destination:/topic/price.stock.MMM {"ticker":"MMM","price":129.45}^@

知道服务器无法发送未经请求的消息非常重要。 来自服务器的所有消息必须是特定的客户端订阅的响应,并且服务器消息的“subscription-id”头必须与客户端订阅的“id”头匹配。 以上概述旨在提供对STOMP协议的最基本的了解。 建议完整地查看协议规范。

4.4.2 好处

不用多说了,不用再造轮子了,直接开干。

4.4.3 启用STMOP

spring-messaging和spring-websocket模块里有STOMP的支持。你可以使用STOMP的endpoint:

import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
  @Override
  public void registerStompEndpoints(StompEndpointRegistry registry) {
    registry.addEndpoint("/portfolio").withSockJS(); //①
  }
  @Override
  public void configureMessageBroker(MessageBrokerRegistry config) {
    config.setApplicationDestinationPrefixes("/app"); //②
    config.enableSimpleBroker("/topic", "/queue"); //③
  }
}

客户端,可以使用JSteunou/webstomp-client:

var socket = new SockJS("/spring-websocket-portfolio/portfolio");
var stompClient = webstomp.over(socket);
stompClient.connect({}, function(frame) {
}

或者通过WebSocket(没有SockJS)

var socket = new WebSocket("/spring-websocket-portfolio/portfolio");
var stompClient = Stomp.over(socket); stompClient.connect({}, function(frame) {
}

Spring Chapter4 WebSocket 胡乱翻译 (一)的更多相关文章

  1. Spring Chapter4 WebSocket 胡乱翻译 (二)

    书接上文,Spring Chapter4 WebSocket 胡乱翻译 (一) 4.4.4. 消息流 一旦暴露了STOMP端点,Spring应用程序就成为连接客户端的STOMP代理. 本节介绍服务器端 ...

  2. Spring Chapter4 WebSocket 胡乱翻译 (一) 一个例子

    因为没有基础,不知道从哪里入手. 文档里的例子,https://github.com/rstoyanchev/spring-websocket-portfolio,这个除了WebSocket,还整了S ...

  3. 玩转spring boot——websocket

    前言 QQ这类即时通讯工具多数是以桌面应用的方式存在.在没有websocket出现之前,如果开发一个网页版的即时通讯应用,则需要定时刷新页面或定时调用ajax请求,这无疑会加大服务器的负载和增加了客户 ...

  4. spring boot websocket stomp 实现广播通信和一对一通信聊天

    一.前言 玩.net的时候,在asp.net下有一个叫 SignalR 的框架,可以在ASP .NET的Web项目中实现实时通信.刚接触java寻找相关替代品,发现 java 体系中有一套基于stom ...

  5. Spring Boot WebSocket从入门到放弃

    在构建Spring boot项目时已经提供webSocket依赖的勾选.webSocket是TCP之上的一个非常薄的轻量级层 ,webSocket主要的应用场景离不开即时通讯与消息推送,但只要应用程序 ...

  6. spring集成webSocket实现服务端向前端推送消息

    原文:https://blog.csdn.net/ya_nuo/article/details/79612158 spring集成webSocket实现服务端向前端推送消息   1.前端连接webso ...

  7. Spring之WebSocket网页聊天以及服务器推送

    Spring之WebSocket网页聊天以及服务器推送 转自:http://www.xdemo.org/spring-websocket-comet/ /Springframework /Spring ...

  8. spring对websocket的集成和使用

    WebSocket是HTML5提出的一个用于通信的协议规范,该协议通过一个握手机制,在客户端和服务端之间建立一个类似于TCP的连接,从而方便客户端和服务端之间的通信. WebSocket协议本质上是一 ...

  9. Spring整合WebSocket

    WebSocket,干什么用的?我们有了HTTP,为什么还要用WebSocket?很多同学都会有这样的疑问.我们先来看一个场景,大家的手机里都有微信,在微信中,只要有新的消息,这个联系人的前面就会有一 ...

随机推荐

  1. 【转】C#控件——DataGridView单元格文本自动换行

    源地址:https://www.cnblogs.com/wangshenhe/archive/2012/07/25/2608324.html DataGridView是.NET开发中常用的控件,在开发 ...

  2. 洛谷P4014 分配问题(费用流)

    传送门 可以把原图看做一个二分图,人在左边,任务在右边,求一个带权的最大和最小完美匹配 然而我并不会二分图做法,所以只好直接用费用流套进去,求一个最小费用最大流和最大费用最大流即可 //minamot ...

  3. maven设置------settings.xml文件学习

    https://blog.csdn.net/tomato__/article/details/13025187 快速预览 maven的配置文件为settings.xml,在下面路径中可以找到这个文件, ...

  4. 使用webpack开发ES6程序的正确姿势

    1.cnpm install babel-loader babel-core babel-preset-es2015 -D 2.cnpm install babel-plugin-transform- ...

  5. 修改两行代码,让nginx支持phpinfo模式

    Nginx服务器默认不支持pathinfo, 在需要pathinfo支持的程序中(如thinkphp),则无法支持”/index.php/Home/Index/index”这种网址. 网上流传的解决办 ...

  6. explian执行计划

    MySQL为我们提供了 explain 关键字来直观的查看一条SQL的执行计划. explain显示了MySQL如何使用索引来处理select语句以及连接表,可以帮助选择更好的索引和写出更优化的查询语 ...

  7. EA添加时序图

    在项目浏览器的空白处右击 http://blog.csdn.net/craftsman1970/article/details/70877530 不同于大部分面向对象或者UML的书籍,在讨论完类图/对 ...

  8. audiosprite的使用

    github地址: https://github.com/tonistiigi/audiosprite 使用方法: http://www.jikexueyuan.com/course/2510_2.h ...

  9. C# 函数参数object sender, EventArgs e

    object sender:表示触发事件的控件对象EventArgs e:表示事件数据的类的基类 Windows程序有一个事件机制.用于处理用户事件. 在WinForm中我们经常需要给控件添加事件.例 ...

  10. HDU - 1907 anti-SG

    题意:nim游戏,最后取光为[输] anti-SG的应用,搬运一下我的摸鱼小笔记 最先看到的应该是分奇偶的非充裕堆判断,若为偶数则先手胜,否则后手胜 按SG分类 SG!=0时 1.只有一堆大于1,先手 ...