Spring Framework 4.0 M1: WebSocket 支持
2019独角兽企业重金招聘Python工程师标准>>>
正如你可能已经看到的,Spring Framework 4.0 第一个里程碑版本已经宣布,且我们已经发布了早期的WebSocket支持。为什么WebSocket重要呢?在web上,需要在客户端(典型如浏览器)和服务器间进行高频率低延迟的消息交换是在应用中必不可少的,它使有效的,双向的通信成为可能。常见的例子包括交易,游戏,协作,数据可视化,其他的一系列场景和用例将随时间而增加。
WebSocket是非常宽泛的话题!你可以在InfoQ上观看我们SpringOne 2012的“WebSocket介绍”获取更全面的介绍。能够简单的使用WebSocket仅仅是一个开始。你将需要一个备用策略用于那些不支持它的浏览器(如 IE < 10)和用于阻止其使用的网络代理。此外,套接字编程,是非常,非常低级的编程。大多数的应用将受益于一个更高级的编程模型。这也是公认的,在WebSocket协议中通过一种机制 来允许使用一个“子协议”(例如一个更高级别的协议),就像今天我们都使用的HTTP,不是一个原始的TCP套接字。例如,子协议包括STOMP,WAMP,和更多其它的。
请记住,这是一个早期版本。它关注的基本面包括JSR-356支持和浏览器内部使用的备选项(fallback options)。也没有子协议支持,那是下一个里程碑版本的目标。
WebSocket的Java API (JSR-356)
WebSocket的Java API是最近完成的并是Java EE 7的一部分。它定义了两种类型的端点—Endpoint子类及注解的端点,如@ClientEndpoint和@ServerEndpoint。完整的介绍超出了本文的范围。我将只会提到在Spring应用中理解如何配置和使用端点的最低要求。
在JSR-356中有两种方法来部署服务器 — 通过Servlet容器扫描(Servlet 3.0特性)和在编程式启动。对于Servlet容器扫描,规范要求注解的端点有一个默认构造器,但Endpoint子类不能被自动部署。相反,Servlet容器扫描检测ServerApplicationConfig类型,其按照预期的循环为每一个Endpoint应用Server/ClientEndpointConfig。
在试图搞清楚这一切之前,你可能想知道的是它如何与你的Spring应用关联。M1版本通过Spring提供了用于初始化两种类型端点的全部支持,包括适当的构造器依赖注入以及每个连接和单例端点生命周期。此外,你应该关闭Servlet容器扫描,其是相当重量级的并扫描所有类包括第三方依赖。
给我代码!
用Spring初始化一个注解的端点,只需简单地用类级别注解配置一个SpringConfigurator:
import javax.websocket.server.ServerEndpoint;
import org.springframework.web.socket.server.endpoint.SpringConfigurator;@ServerEndpoint(value = "/echo", configurator = SpringConfigurator.class)
public class EchoEndpoint {private final EchoService echoService;@Autowiredpublic EchoEndpoint(EchoService echoService) {this.echoService = echoService;}@OnMessagepublic void handleMessage(Session session, String message) {// ...}}
上面的代码假设SpringContextLoaderListener用于装载Spring配置, 但通常是在web应用的情况。除此之外没有别的要求。Servlet容器扫描发现注解的端点和SpringConfigurator为每个WebSocket会话初始化一个新的实例,这也是规范中定义的默认的生命周期。
如果你想使用一个单例或想关闭Servlet容器扫描,声明EchoEndpoint作为一个Spring bean,且也加添加一个forServerEndpointExporter
bean声明(只需一次!)。如下示例使用Spring的Java配置,但你也可以添加基于XML配置等价的声明。
import org.springframework.web.socket.server.endpoint.ServerEndpointExporter;@Configuration
public class EndpointConfig {@Beanpublic EchoEndpoint echoEndpoint() {return new EchoEndpoint(echoService());}@Beanpublic EchoService echoService() {// ...}@Beanpublic ServerEndpointExporter endpointExporter() {return new ServerEndpointExporter();}}
Endpoint子类能连同一个ServerEndpointExporter声明(只需一次)一起通过EndpointRegistration被部署。
import org.springframework.web.socket.server.endpoint.ServerEndpointExporter;
import org.springframework.web.socket.server.endpoint.ServerEndpointRegistration;@Configuration
public class EndpointConfig {@Beanpublic EndpointRegistration echoEndpoint() {return new EndpointRegistration("/echo", EchoEndpoint.class);}@Beanpublic ServerEndpointExporter endpointExporter() {return new ServerEndpointExporter();}// ..}
EndpointRegistration也有一个接受一个端点实例参数的构造器。这允许你在有每个WebSocket会话有一个新实例或单个实例服务所有会话间进行选择。
客户端呢?
JSR-356提供如下API用于连接服务器:
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
container.connectToServer(EchoEndpoint.class, new URI("ws:localhost:8080/webapp/echo"));
这是很简单的,但如果也能声明它也将是不错的。常见的情况是 — 当web应用启动时,它应该自动的连接到远程端点,开始处理消息并当应用关闭时停止。
你可以通过一个如下所示的连接管理器来做到,即当Spring ApplicationContext刷新或关闭时分别进行WebSocket连接建立和关闭。
import org.springframework.web.socket.client.endpoint.AnnotatedEndpointConnectionManager;@Configuration
public class EndpointConfig {// For Endpoint sub-classes use EndpointConnectionManager instead@Beanpublic AnnotatedEndpointConnectionManager connectionManager() {return new AnnotatedEndpointConnectionManager(echoEndpoint(), "ws://localhost:8080/webapp/echo");}@Beanpublic EchoEndpoint echoEndpoint() {// ...}}
你也可以使用autoStartup属性来开启/禁用自动连接。如果禁用,你可以手工调用start()和stop()。
到此总结了JSR-356支持的概述。
Spring WebSocket API
除了JSR-356的支持,这个版本提供了导致一些明显问题的Spring WebSocket API的新的开始。
为什么是我们自己的API?我们在内部它作为更高级服务的基础如SockJS。它允许我们有可能插入额外的Java WebSocket实现并添加额外的特性。例如JSR-356没有提供从一个存在的Servlet初始化WebSocket握手的方式,当添加SockJS支持时这让我们发现非常有用。此外,尽管Jetty也没有提供JSR-356支持,我们也是能够在这个版本插入(所有新的)Jetty 9 WebSocket API和包括Jetty 9支持。我们可以坚持使用Jetty API直接前进,因为它提供了一组更丰富的WebSocket配置和处理选项及比Java WebSocket API更频繁的更新。
为什么仅基于类型(例如,不是注解)?Spring WebSocket API以框架使用为主为目标。应用当然可以使用它,但我们相信,到套接字的编程对于大多数应用来组织他们的业务逻辑和提供健壮的消息处理太低级了。为了更好地体会到这一点,可以考虑如果一个应用暴露单个WebSocket连接(在大多数情况,它应该),它将不得不从单个类中处理所有应用消息类型。即使是注解,不可能自适应实际应用的复杂性。想像一下REST没有名词(URLs)和动词(HTTP methods),仅有原始的socket。这就是为什么子协议支持和更高级别编程模型是非常必要的,这也是我们更像是要有一些注解。
希望注意到“为什么”问题。现在,让我们来看一些代码。
Spring WebSocket API核心接口是WebSocketHandler。下面是对一个它的实现用于处理文本消息。基类有个空方法,只是按照协议中定义的以状态1003(not acceptable)关闭会话来拒绝二进制消息。
import org.springframework.web.socket.adapter.TextWebSocketHandlerAdapter;public class EchoHandler extends TextWebSocketHandlerAdapter {@Overridepublic void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {session.sendMessage(message);}}
注意,handleTextMessage允许异常传播。这不同于JSR-356,它不允许。如果一个Exception(或Throwable)逸出方法,会话会自动以状态1011关闭(server error)。这意味着你可以选择处理异常,如果有任何有意义的事情去做;或者否则让它以默认方式处理。默认异常处理通过WebSocketHandlerDecorator机制提供。它能被扩展和/或替换。这些仅是几个我们自己的API能让我们去做什么的例子。
WebSocketHandler处理器能通过WebSocketHttpRequestHandler
插入到Spring MVC。
import org.springframework.web.socket.server.support.WebSocketHttpRequestHandler;@Configuration
public class WebConfig {@Beanpublic SimpleUrlHandlerMapping handlerMapping() {Map<String, Object> urlMap = new HashMap<String, Object>();urlMap.put("/echo", new WebSocketHttpRequestHandler(new EchoHandler()));SimpleUrlHandlerMapping hm = new SimpleUrlHandlerMapping();hm.setUrlMap(urlMap);return hm;}}
SockJS备选项
SockJS是一个浏览器JavaScript类库,其提供了WebSocket类似的编程模型和一系列特定浏览器的传输(transport),如果WebSocket在浏览器不支持或网络问题阻止它时使用。我们很高兴的宣布在这个版本中支持SockJS。SockJS的更多细节和各种传输选项,请访问sockjs-client项目页面。
开启SockJS支持,简单地声明一个SockJsService,映射它到一些URL,并提供一个用于出入传入消息(incoming message)的WebSocketHandler。注意,WebSocketHandler是之上讨论的相同的处理器。换句话说,当使用SockJS,编程模型仍然相同,但底层传输可能改变为HTTP流,长轮询,或其他的东西是必要的。
import org.springframework.web.socket.sockjs.SockJsService;
// ...@Configuration
public class WebConfig {@Beanpublic SimpleUrlHandlerMapping handlerMapping() {SockJsService sockJsService = new DefaultSockJsService(taskScheduler());Map<String, Object> urlMap = new HashMap<String, Object>();urlMap.put("/echo/**", new SockJsHttpRequestHandler(sockJsService, new EchoHandler()));SimpleUrlHandlerMapping hm = new SimpleUrlHandlerMapping();hm.setUrlMap(urlMap);return hm;}@Beanpublic ThreadPoolTaskScheduler taskScheduler() {ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();taskScheduler.setThreadNamePrefix("SockJS-");return taskScheduler;}}
如果你想知道之上 的任务调度用于各种SockJS相关的任务,例如在HTTP流请求上定期发送心跳信息(以防止代理认为连接是不新鲜的),移除过期的SockJS会话等。
最后
可以在Github上找到一个示例和介绍的项目。它包括配置JSR-356端点的示例,Spring WebSocketHandler,以及SockJS服务。对于所有示例,建议使用Google Chrome网络选项卡开发工具,为了观察WebSocket和HTTP流量,观察错误等。
如果您有反馈意见和建议,我们很乐意听到它!
原文:http://blog.springsource.org/2013/05/22/spring-framework-4-0-m1-websocket-support/
相关阅读:
Spring Framework 4.0M1 & 3.2.3 发布了
JSR-356 WebSocket API规范中文版
Servlet 3.1规范
转载于:https://my.oschina.net/qjx1208/blog/200931
Spring Framework 4.0 M1: WebSocket 支持相关推荐
- 具有Java 8支持的Spring Framework 4.0.3和Spring Data Redis 1.2.1
Spring Framework 4.0.3 正如Spring社区宣布的那样,Spring Framework 4.0.3现在可用. 它是上周Java 8发布后框架的第一个版本,因此它是使用OpenJ ...
- 振作起来– Spring Framework 4.0即将来临!
几天前,SpringSource 宣布流行的Spring框架的4.0版本正在开发中. 下一个迭代将是Spring Framework 4.0! 如SpringSource所言,即将发布的版本的重点是& ...
- Spring学习总结(23)——Spring Framework 5.0 新特性
Spring Framework 5.0 是自 2013年12月版本 4 发布之后 Spring Framework 的第一个主发行版.Spring Framework 项目的领导人 Juergen ...
- Spring Framework 5.0.0.M4中文文档第3章
文章目录 Part II. 核心技术 3. IoC容器 3.2 容器概述 3.2.1 配置元数据 3.2.2 实例化容器 3.2.3 使用容器 3.3 Bean概述 3.3.1 命名bean 3.3. ...
- Spring Boot 3.0 M1 发布,正式弃用 Java 8,最低要求 Java 17。。。
一直以来,Java8都是Java社区心头的痛.因为它代表着以稳定性为主的企业管理层,与拥抱变化为主的底层码农层之间的.爱的魔力拉锯战. 不生!少生!成为各大厂心照不宣的选择. 现在,这种平衡或将打破. ...
- Spring Framework 3.2 M1发布
SpringSource刚刚宣布了针对Spring 3.2的第一个里程碑版本. 现在可以从SpringSource存储库(位于http://repo.springsource.org/)获得新版本. ...
- Spring Boot 3.0.0 发布第一个里程碑版本M1,你的 Java 升到 17 了吗?
欢迎关注方志朋的博客,回复"666"获面试宝典 文章来源:程序猿DD 2022年1月20日,Spring官方发布了Spring Boot 3.0.0的第一个里程碑版本M ...
- Spring Cloud 2022.0.0 M1 发布:需Java 17、兼容Spring Boot 3
各位小伙伴们,复工第一天,DD祝大家新年快乐!这个新年真的是好好休息了一下,文章也没有更,新闻也没怎么看.所以,新年第一篇就先带大家一起回顾下春节期间的一些新动态.从Spring官方信息看,这几天主要 ...
- 前瞻:Spring 6.0将停止支持Freemarker和JSP
Spring Framework 6.0 第一个里程碑版本已经发布,目前已经可以从Spring Repo获取.这里有一些新变更我们可以提前了解一下.请大家踊跃留言.点赞.转发.再看. Java EE迁 ...
- Spring Session 2.0.0.M1 发布,分布式解决方案
我很高兴地宣布Spring Session 2.0.0.M2 发布了.此版本的重点主要是确保与Spring Framework 5.0.0.RC2和Spring Data Kay-M4的兼容性.我们期 ...
最新文章
- fiddler 抓取winform wcf包
- 流程控制关键字——分支结构
- Linux命令:MySQL系列之五--SELECT单表查询、多表查询升级及删除,插入
- Git 安装和使用教程(Windows)
- python输出数据到excel-python如何导出数据到excel文件
- java子类对象不能调用父类protected方法和域的原因。
- 图卷积网络是什么?(行为识别)
- 【转】HTTP协议中PUT和POST使用区别
- Mysql服务器线上配置主从同步
- 查询结果取交集_Elasticsearch 查询过程中的 prefilter 原理
- SQL Server更新某一列中多个字典码对应内容(sql示例)
- java中一个数小于零_这段java程序怎样才能让“所输入的数小于0!”只输出一次,并且满足题目条件?...
- 欧拉和格拉斯曼解释平行宇宙
- Java知多少(79)哈希表及其应用
- ubuntu14.04小米无线网卡驱动安装
- python高维数据可视化_【机器学习】(十六)主成分分析PCA:高维数据可视化、特征提取...
- mysql限制小数位_mysql-控制小数位数
- 祝大家新年快乐,前兔似锦!
- 《系统架构设计》-01-架构和架构师概述
- MongoDB:常见的面试题和答案
热门文章
- Node.js CVE-2017-14849复现(详细步骤)
- Failed to create the java virtual machine完全解决办法
- 解读前端开发工程师必备技能
- std::string与output-operator的兼容问题
- iphone中扫描wifi热点
- 2019 The Preliminary Contest for ICPC China Nanchang National Invitational
- 使用npm uninstall卸载express无效
- Bitmap-把方形图片处理为圆形
- 最近好闷,什么时候才有需求啊,很郁闷
- 入门命令14-文件替换:replace