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. vue2.0使用ES6语法

    ES6 快速入门 什么是ES6? ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准,已经在2015年6月正式发布了.Mozilla公司将在这个标准的基础上,推出Java ...

  2. model中的Meta类

    通过一个内嵌类 "class Meta" 给你的 model 定义元数据, 类似下面这样: class Foo(models.Model): bar = models.CharFi ...

  3. 开发效率神器 uTools - 偏前端和 UI

    本文首发于:Bougie's Blog - 效率神器 uTools 前言 今天组内公众号推荐了 Mac 上的效率神器 Alfred. 详情链接:效率神器 Alfred workflow 插件推荐 早上 ...

  4. Linux硬件信息采集

    dmidecode: 简介: dmidecode命令通过读取DMI数据库获取硬件信息并输出.由于DMI信息可以人为修改,因此里面的信息不一定是系统准确的信息 dmidecode遵循SMBIOS/DMI ...

  5. redis读取自增时候指定的key问题

    首先,此文章是接了如下文章写的 Spring boot redis自增编号控制 踩坑 上面这个问题解决后,公司这边功能其实已经实现了,但是考虑到一种情况,因为我们这边号的生成就是根据上面的自增编号来的 ...

  6. 5、用Numpy实现结构体

    1.结构数组: 在C语言中我们可以通过struct关键字定义结构类型,结构中的字段占据连续的内存空间,每个结构体占用的内存大小都相同,因此可以很容易地定义结构数组.和C语言一样,在NumPy中也很容易 ...

  7. AndroidManifest.xml警告

    新建一个android项目后,AndroidManifest.xml有一个黄色警告 作为一个新手,不知道这个警告来自哪里,点击界面下方的不同标签,才知道来自图中的位置 第8行中,application ...

  8. 说说Cookie和Session(会话)的区别?

    1.Cookie 通俗讲,是访问某些网站后在本地存储的一些网站相关信息,下次访问时减少一些步骤.更准确的说法是:Cookies是服务器在本地机器上存储的小段文本并随每一个请求发送至同一服务器,是在客户 ...

  9. Javascript 中 的坑..

    ### 1. 0 == '' 返回 true 0 === '' 返回false......... 切记...

  10. c3m快速入门