最近在学习有个配置中心(nacos 和 apollo),配置中心在配置变更时通过 http 长连接的方式进行通知。

(1)配置客户端定时向配置中心发送请求获取最新配置(apollo客户端会像服务端发送长轮训http请求,超时时间60秒,当超时后返回客户端一个304 httpstatus,表明配置没有变更,客户端继续这个步骤重复发起请求,当有发布配置的时候,服务端会调用DeferredResult.setResult返回200状态码,然后轮训请求会立即返回(不会超时),客户端收到响应结果后,会发起请求获取变更后的配置信息。

(2)当服务器配置变更时会通过与客户端建立的长连接立即通知客户端。

HTTP 长连接

HTTP是无状态的 ,也就是说,浏览器和服务器每进行一次HTTP操作就要建立一次连接,当任务结束就中断连接。如果客户端浏览器访问的某个HTML或其他类型的Web页中包含其他Web资源,如JavaScript文件、图像文件、CSS文件等,此时就要建立一个新的HTTP会话。

HTTP1.1和HTTP1.0相比较而言,最大的区别就是增加了持久连接支持,但还是无状态的或者说是不可靠的。如果浏览器或服务器在其头信息中加入了这行代码:Connection:keep-alive,TCP连接在发送后将仍保持打开状态,于是浏览器可以继续通过相同的连接发送请求。保持连接节省了为每个请求建立连接的时间,还节约了带宽。

实现长连接要求客户端和服务端都支持长连接。

如果web服务器端看到这里的值为“Keep-Alive”,或者看到请求使用的是HTTP 1.1(HTTP 1.1默认进行持久连接),它就可以利用持久连接的优点,当页面包含多个元素时(例如Applet,图片),显著地减少下载所需要的时间。要实现这一点, web服务器需要在返回给客户端HTTP头信息中发送一个Content-Length(返回信息正文的长度)头,最简单的实现方法是:先把内容写入ByteArrayOutputStream,然 后在正式写出内容之前计算它的大小

无论客户端浏览器 (Internet Explorer) 还是 Web 服务器具有较低的 KeepAlive 值,它都将是限制因素。例如,如果客户端的超时值是两分钟,而 Web 服务器的超时值是一分钟,则最大超时值是一分钟。客户端或服务器都可以是限制因素

在header中加入 --Connection:keep-alive 
在HTTp协议请求和响应中加入这条就能维持长连接。 
再封装HTTP消息数据体的消息应用就显的非常简单易用

DeferredResult 异步请求处理

支持:

在Servlet 3.0中,我们可以从HttpServletRequest对象中获得一个AsyncContext对象,该对象构成了异步处理的上下文,Request和Response对象都可从中获取。AsyncContext可以从当前线程传给另外的线程,并在新的线程中完成对请求的处理并返回结果给客户端,初始线程便可以还回给容器线程池以处理更多的请求。如此,通过将请求从一个线程传给另一个线程处理的过程便构成了Servlet 3.0中的异步处理。

示例:

浏览器请求地址:http://localhost:8080/data 不会立即返回结果,客户端与服务端建立长连接,5秒服务端处理结束后返回结果。

@SpringBootApplication
@RestController
public class ConfigClientApplication {@RequestMapping("/data")public DeferredResult<String> getData(){DeferredResult<String> result = new DeferredResult<>();Thread thread = new Thread(() ->{try {//与客户端建立长连接之后 5秒之后返回结果Thread.sleep(5000);result.setResult("hello world");}catch (Exception e){}});thread.start();return result;}public static void main(String[] args) {SpringApplication.run(ConfigClientApplication.class, args);}
}

实现原理:

Controller 返回结果 DeferredResult<String> 最终由 DeferredResultMethodReturnValueHandler 进行处理

public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {if (returnValue == null) {mavContainer.setRequestHandled(true);} else {DeferredResultAdapter adapter = this.getAdapterFor(returnValue.getClass());if (adapter == null) {throw new IllegalStateException("Could not find DeferredResultAdapter for return value type: " + returnValue.getClass());} else {DeferredResult<?> result = adapter.adaptToDeferredResult(returnValue);WebAsyncUtils.getAsyncManager(webRequest).startDeferredResultProcessing(result, new Object[]{mavContainer});}}}

在 WebAsyncManager 中 会进行各种拦截器处理运行,并返回结果

public void startDeferredResultProcessing(final DeferredResult<?> deferredResult, Object... processingContext) throws Exception {Assert.notNull(deferredResult, "DeferredResult must not be null");Assert.state(this.asyncWebRequest != null, "AsyncWebRequest must not be null");Long timeout = deferredResult.getTimeoutValue();if (timeout != null) {this.asyncWebRequest.setTimeout(timeout);}List<DeferredResultProcessingInterceptor> interceptors = new ArrayList<DeferredResultProcessingInterceptor>();interceptors.add(deferredResult.getInterceptor());interceptors.addAll(this.deferredResultInterceptors.values());interceptors.add(timeoutDeferredResultInterceptor);final DeferredResultInterceptorChain interceptorChain = new DeferredResultInterceptorChain(interceptors);this.asyncWebRequest.addTimeoutHandler(new Runnable() {@Overridepublic void run() {try {interceptorChain.triggerAfterTimeout(asyncWebRequest, deferredResult);}catch (Throwable ex) {setConcurrentResultAndDispatch(ex);}}});if (this.asyncWebRequest instanceof StandardServletAsyncWebRequest) {((StandardServletAsyncWebRequest) this.asyncWebRequest).setErrorHandler(new StandardServletAsyncWebRequest.ErrorHandler() {@Overridepublic void handle(Throwable ex) {deferredResult.setErrorResult(ex);}});}this.asyncWebRequest.addCompletionHandler(new Runnable() {@Overridepublic void run() {interceptorChain.triggerAfterCompletion(asyncWebRequest, deferredResult);}});interceptorChain.applyBeforeConcurrentHandling(this.asyncWebRequest, deferredResult);startAsyncProcessing(processingContext);try {interceptorChain.applyPreProcess(this.asyncWebRequest, deferredResult);deferredResult.setResultHandler(new DeferredResultHandler() {@Overridepublic void handleResult(Object result) {result = interceptorChain.applyPostProcess(asyncWebRequest, deferredResult, result);setConcurrentResultAndDispatch(result);}});}catch (Throwable ex) {setConcurrentResultAndDispatch(ex);}}

简单理解为最终通过异步返回结果,客户端与服务端之间通过长连接来保持通信。

参考文章:

https://www.cnblogs.com/code-sayhi/articles/10191526.html

https://blog.csdn.net/qq_42164670/article/details/83214016

Spring Web 学习 -- DeferredResult 长连接异步返回相关推荐

  1. Web 通信 之 长连接、长轮询(long polling)

    Web 通信 之 长连接.长轮询(long polling) 基于HTTP的长连接,是一种通过长轮询方式实现"服务器推"的技术,它弥补了HTTP简单的请求应答模式的不足,极大地增强 ...

  2. java web tcp长连接超时时间_常用java web容器http长连接超时设置

    1.http长连接相关知识 http长连接对我们来说并不陌生,但长连接并不是永远不会关闭.对于HTTP长连接需要注意下面几点:keepalive_timeout指的是web服务器发送完最后一个响应报文 ...

  3. spring mvc学习(49):返回json数据

    json包下载 pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http ...

  4. WEB服务器-长连接与短连接

    WEB静态服务器 长连接与短链接 什么是长连接.短连接? 在HTTP/1.0中默认使用短连接.也就是说,客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接.当客户端浏览器访问的某 ...

  5. 1、JAVA web学习笔记

    以下内容是在学习某机构视频过程中记录的笔记,不准确的地方请大家评论指正. JavaWeb是使用Java语言开发基于互联网的项目. 资源分类有两类: 静态资源: 使用静态网页开发技术发布的资源. 特点: ...

  6. socket的长连接、短连接、半包、粘包与分包

    socket的半包,粘包与分包的问题和处理代码:http://blog.csdn.net/qq_16112417/article/details/50392463 知乎关于长连接和短连接:https: ...

  7. c++ socket 连接超时_Web性能优化之-HTTP长连接

    前言: 当我们使用浏览器访问一个Web站点的时候,我们的电脑会和Web服务器建立一条HTTP的连接,那么在这个连接层面是否可以进行性能优化呢?下面我们要讲解的就是HTTP的长连接和短连接的相关知识. ...

  8. maven mybatis mysql_Java Web学习系列——Maven Web项目中集成使用Spring、MyBatis实现对MySQL的数据访问...

    标签: 本篇内容还是建立在上一篇Java Web学习系列--Maven Web项目中集成使用Spring基础之上,对之前的Maven Web项目进行升级改造,实现对MySQL的数据访问. 添加依赖Ja ...

  9. HTTP学习:关于长连接、短连接、持久连接介绍

    转自:微点阅读  https://www.weidianyuedu.com 什么是Http长连接 长连接定义: client方与server方先建立连接,连接建立后不断开,然后再进行报文发送和接收.这 ...

最新文章

  1. 解题报告:luoguP2868 Sightseeing Cows G(最优比率环,负环判定,二分答案)
  2. Apex Integration Overview
  3. python使用tkinter可以在多个操作系统_在tkinter GUI中使用多个窗口
  4. java label api_使用python API进行的培训作为Java API中LabelImage模块的输入?
  5. 滴滴回应高额抽成:确实存在;抖音火山版被判赔腾讯 800 万元;华为鸿蒙系统有望下月规模化推送|极客头条...
  6. Redis学习手册(目录)
  7. 淘宝开源的代码质量检测工具,太强大了!!
  8. 十六进制数相加校验和计算程序
  9. 考研常识-总结1(硕士、专硕;非全日制、全日制)
  10. 百度AI开放平台[Python]
  11. javascript机器学习
  12. 阿里云ECS服务器CentOS6.5vnc连接时报错Failed to connect to socket /tmp/dbus-xxxxxxx: Connection refused
  13. STM8S---IO复用配置(STVP方式)
  14. Enterprise Architect 中文版 注册码 破解 亲测有效!
  15. 位与:一个数1的结果
  16. PDAL:OSGeo4W安装配置测试PDAL
  17. mysql事务隔离级别详解_MySQL的事务隔离级别详解
  18. 怎么把图片保存到考生文件夹_请在考生文件夹下完成如下操作
  19. 了解如何在Microsoft Word中使用导航窗格
  20. python例子高考志愿填报系统入口_2020高考志愿填报系统入口

热门文章

  1. 此“徐三多”非彼“许三多”?
  2. SpringBoot多环境动态环境切换(nacos)
  3. C++ isalpha()
  4. CSS 层叠样式表书写位置
  5. element ui rules校验记录,方便后续使用
  6. docker mysql默认ip_Docker设置固定ip地址
  7. Web 窗体简介(入门者必看)
  8. VR数字展厅——助力商企实现数字化营销展示
  9. 两种经典最短路径算法
  10. 基础打好了,上层建筑就容易获得了