彻彻底底给你讲明白啥是SpringMvc异步处理


来源 | 编程新说

责编 | Carol

出品 | CSDN云计算(ID:CSDNcloud)

生活在这个世界上,我们必须承认任何事物都是运动变化着的,没有什么东西是一成不变的。

不仅因为这句话是出自马克思主义哲学的唯物辩证法,而且事实确实如此。下面就来描述这样的一个变化。

分工的产生与协作


想必大家都买过房或终将会买房,那自然离不开装修,就以装修这个话题来展开吧。假设有一个搞装修的人叫小王。

小王活儿做得特别好,但目前还是一个人单打独斗。他正在干活儿的这家业主的邻居发现了他的活儿好,于是专门来找他咨询情况。

小王不得不停下手头的工作,来为潜在的客户解答疑惑或诉说方案。最终靠实力把潜在客户变成了真正的客户。小王的名气就这样传开了。

附近小区的人闻名而来,找他沟通装修方案或确认时间安排,小王不得不每次都停下手头工作,专心为客户解答。等客户走后,他再开始继续工作。

随着来找他的人与日俱增,渐渐的小王发现他真正用于干活儿的时间越来越少了,因为他在接待客户上花费了太多的时间。

但没有办法,为了能够接到更多的活儿,他必须为客户提供这个咨询,必须要花掉这些时间。结果导致干活儿的时间被压缩了,活儿干不完了,该咋办呢?

其实解决方法很简单,所有人都能想得到,那就是小王招了一个工人专门给他干活。工人干完活后先过小王这一关,小王觉得可以了才会交付给业主。

小王呢则继续为客户提供咨询服务,在空闲的时候也会去和仅有的一个工人一起干活。看来问题已得到解决,一切重新回到平衡状态中。

由于小王走了狗屎运,每天来的客户实在是太多了,这个刚刚建立的平衡又被打破了。小王不得不全天候的提供咨询,索性不再干活了。

而且由于接的活儿越来越多,无奈不得不又招了第二个工人,第三个工人,第四个。。。

我们可以看到很多事情都在逐渐的发生着改变,小王从一个只会干活的工人逐步过渡到只负责接待客户的顾问,不再干活。

为了适应自己的这个新角色,小王不得不招了一个又一个工人为自己干活,这样自己才能得以从原来的工作中彻底解脱。

可见随着事物的发展,分工的产生是一种必然,这就导致了岗位种类的增加。原来只有一个岗位,既负责干活又负责咨询。

现在变为了两个岗位,一个专门负责咨询和监工,其实就是工长了,一个专门负责干活和施工,其实就是工人。

这种“工长 + 工人”的模式在现实生活中使用的非常普遍,工长为工人分配工作和验收工人的工作以及解答工人的问题,其实就是两个岗位之间的协作。

因此,分工的产生与协作代表着一种更加先进和高效的生产方式,至少从理论上来看是这样的,他们各司其职,然后再强强联合,结果可想而知。

Web容器对异步的支持

看完上一小节,希望大家记住这八个字,“各司其职、相互协作”。OK,马上进入程序世界。

SpringMvc的实质就是对Java Web的封装,因此为了更容易的理解SpringMvc的异步,必须先了解Java Web的异步。

Java Web的实质就是一套标准(接口),Web容器实现了这套标准,所以我们站在Web容器的立场来说Java Web的异步,非常好理解。

无论采用什么框架开发的Java Web应用,最终都是在Web容器中运行的,如tomcat就是最常用的Web容器。

启动SpringBoot时,可以看看日志中打印出的线程名称,其实就是tomcat线程池里的线程。可以多请求几次,发现每次处理请求的线程Id都不一样。

我们知道,其实每一个请求过来后,Web容器都会从自己的线程池中拿出一个线程来运行Java Web应用以处理请求。当请求处理完后,这个线程会被还回到线程池中以便处理下一个请求。

如果请求能在非常短的时间内处理完成,是没有问题的。我们设想一下,如果请求执行的非常慢,那么这个线程将无法还回去,于是线程池中可用的线程数目将少一个。

由于线程池的容量是有限的,如果很多执行的很慢的请求同时到来,那么线程池中的线程将会用光,而且短时间内都还不回来。此时的其它请求都将无法被处理。

我们发现执行很快的请求和非常耗时的请求是属于两种不同性质的事物,现在它们都由Web容器的线程池的线程来从头处理到尾,就像当初的小王。

既要接待客户做咨询工作,又要等客户走了自己干活。这显然是低效的,唯一的方法就是将这两种工作分开,分别交由两个岗位去做。

于是我们就看到,小王招了很多工人,自己专业做咨询接活儿,转手把活儿交给工人去做,工人做好后把活儿再交回给小王,小王再向业主交付。

我们可以把这个思路套到Web容器上,就是Web容器线程池的线程只用来处理执行速度很快的请求,这对应于小王只负责咨询接活儿。

对于非常耗时的请求,Web容器线程池的线程将把这个请求交给其它专门的线程池的线程去处理,这对应于小王把接到的活儿交给他的工人去做。

Web容器线程池的线程将再去接受其它请求,因为耗时的请求已经被交出去了。这对应于小王再去接别的活儿,因为上一个活儿已经交给工人去干了。

专门的线程池的线程处理完这个请求后会把它还回给Web容器线程池的线程,这对应于工人干完活儿后会把活儿先交给小王去验收。

Web容器线程池的线程拿到处理结果,把结果写入响应,这个请求就被处理完毕了。这对应于小王把工人干好的活儿交付给业主,施工就算完毕了。

我们来分析一下,小王由于角色转变而带来的工作转变都有哪些。一开始小王单打独斗,小王工作有三种,小王从业主接活儿,小王自己干活,小王向业主交付。

到最后小王成了工长,此时的工作是四种,小王从业主接活儿,小王把活儿交给工人去做,工人把做好的活儿交回给小王,小王向业主交付。

对比后发现,小王为了使自己不干活,所以引入了工人,以及由此产生的他与工人之间的一去一来的协调交互。

同样来分析一下,Web容器线程池的线程前前后后有哪些变化。一开始线程处理所有的请求,可以分为三个阶段,线程接受请求,线程处理请求,线程写回响应。

到最后线程的工作分为四个阶段,线程接受请求,线程把待处理的请求交给专门的线程池,专门的线程池把处理好的请求交回给线程,线程写回响应。

对比后发现,Web容器线程池的线程为了使自己不处理耗时请求,所以引入了专门的线程池,以及由此产生的它与专门的线程池的一去一来的协调交互。

是不是发现线程池和小王的行为是完全对应的。而且他们面临的问题都一样,就是把需要处理的任务交出去给别人,别人把处理完毕的任务再还回给他。

好了,现在我来告诉你,这就是Java Web异步处理的整体逻辑思想。化繁为简后,其实就是一去一来这两个动作罢了。

自己把执行流程交出去

1AsyncContext startAsync()


别人把执行流程还回来

1void dispatch()


上面这两个方法就完成了一去一来这两个动作,仅此而已。

看到这些,可能有些人大失所望,传说中“牛X和高大上”的异步处理,到最后也不过区区十四个字,“执行流程交出去,执行流程还回来”。

可能还会有人觉得,异步处理不应该和客户端也有关系吗?其实并没有,纯粹是服务器端的把戏。而且对于单个请求的处理时间也不会减少。

就像你去饭店吃饭,你点的这份饭在后厨是一个厨师完成的还是多个厨师协作完成的,其实你并不知道,一般情况下你也并不关心。

SpringMvc对异步的支持

上面描述的异步处理逻辑只是一个规范(接口),是不带实现的。任何想要支持Java Web异步处理的,需要在遵守这个规范的前提下,自己提供一套实现。

说白了,就是也要采用交出去还回来的模式,但是如何交出去,怎样还回来,要自己去实现,还有这个专门的线程池也要自己来提供。

SpringMvc提供了对异步的支持,所以它遵守了这个规范,而且它也定义了相似的接口来与Java Web规范交互。

这个接口就是AsyncWebRequest,它的实现类是StandardServletAsyncWebRequest。同样的两个方法。

交出去

1void startAsync()


还回来

1void dispatch()



在这两个方法的实现中,分别去调用了Java Web规范中的对应方法,这就是与Java Web规范的交互。

同时SpringMvc自己是有线程池的,所以在第一个方法里实现了把执行流程交出去的操作,在第二个方法里实现了把执行流程还回来的操作。

还有一个问题就是,并不是所有的方法都需要异步处理,所以就需要有一种方式来告诉SpringMvc,哪个方法需要异步处理。

SpringMvc选择了采用方法返回值的类型来进行区分,凡是@RequestMapping方法的返回值类型是以下这些的,就表明开发人员想进行异步处理,于是SpringMvc就进行异步处理。

 1Callable<V>23DeferredResult<T>45WebAsyncTask<V>67StreamingResponseBody89ResponseEntity<StreamingResponseBody>
10
11ResponseBodyEmitter
12
13ResponseEntity<ResponseBodyEmitter>


对于异步处理的方式,其实也包括两大类,一类是开发人员不管,完全交给SpringMvc去处理,一类是开发人员自己把控,不用SpringMvc参与。

对于第一类,我们返回Callable<V>类型就可以了,这样SpringMvc会把它提交到线程池里去执行。


对于第二类,我们返回DeferredResult<T>类型即可,它的意思是延迟结果,就是需要延迟一会才会有结果,但是如何延迟呢,SpringMvc并不会去管。


因此是由开发人员来决定的,开发人员需要自己弄个线程去执行,并且一定要记住最后要设置一下结果才行。

我们看到耗时的代码都跑到别的线程里去执行了,那么SpringMvc的处理主流程自然就结束了,这就是执行流程交出去的过程。

只不过有一点需要注意,这个请求的处理并没有完成,只是暂时离开了SpringMvc的主流程,在别的线程池里运行着呢。

那么一段时间后,别的线程池运行结束,已经取得了结果,那这个结果和执行流程又该如何还回来呢?

直接还回来吗?显然是不可能的,因为SpringMvc的处理主流程在把任务交出去的那一刻就已经结束了、不存在了。

其实是别的线程池在处理结束并得到结果后,处理流程连同结果会返回到Web容器中,由Web容器再次分派这个请求到SpringMvc中来。

这就是为什么上面第二个方法的名字叫做dispatch的原因,就是再次分派这个请求到Web应用中来嘛,因此会再次进入到SpringMvc中,这不就把执行流程还回来了嘛。

可能会有人产生疑惑,如果SpringMvc再次处理这个请求那不就乱套了吗?答案是显然不会的,因为这次异步的结果已经存在了,自然不会再异步处理了,而是把它跳过去直接进入后续处理。

也就是对方法返回值(ReturnValue)的处理,比如序列化成JSON写入响应,或进行视图渲染,把渲染后的视图写入响应,这样这个请求就算处理完毕了。

推荐阅读:超级干货!31 条2020 年最新版 ZooKeeper面试题,先收藏再看!| 博文精选
2020云计算,是四强争霸还是赢家通吃?
我眼中的分布式系统可观测性
被盗巨鲸用户可能遭到了持续性攻击
LSTM之父发文:2010-2020,我眼中的深度学习十年简史
复工第一周:食堂吃出了高考的感觉……
真香,朕在看了!点击“阅读原文”,参与调查

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/519144.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

选择阿里云数据库HBase版十大理由

根据Gartner的预计&#xff0c;全球非关系型数据库&#xff08;NoSQL&#xff09;在2020~2022预计保持在30%左右高速增长&#xff0c;远高于数据库整体市场。 阿里云数据库HBase版也是踏着技术发展的节奏&#xff0c;伴随着NoSQL和大数据技术的兴起和发展&#xff0c;从2010年…

酷睿i7cpu适合的linux,CPU性能篇 - Core i7-4770K Linux之旅:有喜有忧_Linux新闻_Linux公社-Linux系统门户网站...

CPU性能篇——Rodinia是学术界经常使用的科学测试工具。OpenMP LavaMD负载中&#xff0c;4770K相比3770K快了12&#xff05;&#xff0c;8350表现也可以。OpenMP Leukocyte负载里&#xff0c;4770K对比3770K的优势依然有10&#xff05;&#xff0c;但是8350大亮了&#xff0c;竟…

GitOps:Kubernetes多集群环境下的高效CICD实践

为了解决传统应用升级缓慢、架构臃肿、不能快速迭代、故障不能快速定位、问题无法快速解决等问题&#xff0c;云原生这一概念横空出世。云原生可以改进应用开发的效率&#xff0c;改变企业的组织结构&#xff0c;甚至会在文化层面上直接影响一个公司的决策&#xff0c;可以说&a…

远程办公是一阵“过渡风”还是会“继续燃烧”?

受中国新型冠状病毒肺炎感疫情的影响&#xff0c;2月伊始&#xff0c;「远程办公」成为所有人关心与讨论的热门话题之一。在现实驱动之下&#xff0c;企业如何协同与高效办公成为重点问题中的焦点。在中国企业与「远程办公」正面相遇满月之际&#xff0c;2月29日&#xff0c;CS…

SpringBoot+Shiro+ehcache实现登录失败超次数锁定帐号

文章目录二、Controller层接收登录请求三、自定义的Realm四、密码验证器增加登录次数校验功能五、ShiroConfig的配置类六、EhCache 的配置七、全局异常的配置####### 一、 Shiro的执行流程1、核心介绍1&#xff09;Application Code用户编写代码2&#xff09;Subject就是shiro管…

linux putty 字体,putty修改字体配色

先看效果步骤&#xff1a;1. 打开Windows注册表编辑器开始 -> regedit2. 找到putty默认session所在位置HKEY_CURRENT_USER\Software\SimonTatham\PuTTY\Sessions\Default%20Settings3. 右键导出修改# 字体(monaco字体不错&#xff0c;如效果图)"Font""Consol…

90后ACE成长记——从偏居一隅小城里走出的核心技术人

《ACE成长记》栏目说明 名词解释&#xff1a; 阿里云工程师&#xff0c;简称 ACE &#xff08;Alibaba Cloud Engineer&#xff09;&#xff0c;代表云计算的爱好者&#xff0c;是最“王牌”&#xff08;ACE&#xff09;的一群开发者&#xff0c;也是未来的MVP。 ACE 是遍布在…

阿里开发者招聘节 | 面试题01:如何实现一个高效的单向链表逆序输出?

面试&#xff0c;如同玩一场饥饿游戏&#xff1a;既要对环境了然于胸&#xff0c;又要对自身心知肚明。发现一个好工作不容易&#xff0c;但成功应聘又会面临一系列的挑战。 为帮助开发者们提升面试技能、有机会入职阿里&#xff0c;云栖社区特别制作了这个专辑——阿里巴巴资…

从Kubernetes安全地访问AWS服务,告诉你多云场景下如何管理云凭据!

作者| Alexey Ledenev翻译 | 天道酬勤&#xff0c;责编 | Carol出品 | CSDN云计算&#xff08;ID&#xff1a;CSDNcloud&#xff09;随着企业与各种云提供商合作&#xff0c;多云场景已经变得十分常见。在谷歌Kubernetes引擎&#xff08;GKE&#xff09;上运行的应用程序需要访…

MSSQL-最佳实践-Always Encrypted

摘要 在SQL Server安全系列专题月报分享中&#xff0c;往期我们已经陆续分享了&#xff1a;如何使用对称密钥实现SQL Server列加密技术、使用非对称密钥实现SQL Server列加密、使用混合密钥实现SQL Server列加密技术、列加密技术带来的查询性能问题以及相应解决方案、行级别安…

java实现对文件加解密操作

源文件&#xff1a; 加密后的文件&#xff1a; 解密后的文件&#xff1a; package com.gblfy.test;import java.io.*;/*** java 实现对文件加解密的方法** author gblfy* date 2020-12-08*/ public class IOSercet {//获取系统类型private static String OS System.getPro…

如何在工作中快速成长?致工程师的10个简单技巧

阿里妹导读&#xff1a;阿里有句非常经典的土话&#xff0c;“今天的最好表现&#xff0c;是明天的最低要求。”如何挖掘潜能、发现更好的自己&#xff1f;今天&#xff0c;阿里巴巴高级无线开发专家江建明将认知升级的方法总结出来&#xff0c;帮助你获得快速成长的秘诀&#…

1 手写第一个Win32窗口程序

1 基础概念 什么是窗口&#xff1f; 答&#xff1a;窗口就是屏幕上的一片区域&#xff0c;接受用户的输入&#xff0c;显示程序的输出。可以包含标题栏、菜单栏、工具栏以及控件等。什么是句柄&#xff1f; 答&#xff1a; 作为一种管理和操作系统资源的机制&#xff0c;提供了…

解析云原生与云计算本质区别,别再傻傻分不清楚了!

来源| comparethecloud翻译 | 天道酬勤&#xff0c;责编 | Carol出品 | CSDN云计算&#xff08;ID&#xff1a;CSDNcloud&#xff09;云应用程序是热门话题。很多时候&#xff0c;我们会遇到像云原生应用程序和云计算应用程序这样的术语。首先&#xff0c;很少有人同时使用这两…

阿里开发者招聘节 | 面试题02-04:给定一个二叉搜索树(BST),找到树中第K小的节点

为帮助开发者们提升面试技能、有机会入职阿里&#xff0c;云栖社区特别制作了这个专辑——阿里巴巴资深技术专家们结合多年的工作、面试经验总结提炼而成的面试真题这一次将陆续放出&#xff08;面试题官方参考答案将在专辑结束后统一汇总分享&#xff0c;点此进入答题并围观他…

确认!别再相信Python了! 程序员:就你敢说...

程序员你有没有感觉到&#xff0c;Python最近已经刷屏到爆炸了&#xff1f;细分析Python之所以刷屏&#xff0c;主要是因为人红是非多&#xff0c;在编程界它是一种特殊的存在&#xff0c;有人认为&#xff0c;只有用Python才能优雅写代码&#xff0c;提高代码效率&#xff1b;…

云原生的新思考,为什么容器已经无处不在了

4月24日&#xff0c;中国信息通信研究院主办的首届云原生产业大会在北京举行&#xff0c;在《云原生数字引领未来》的主题演讲中&#xff0c;阿里云容器服务总监易立表示&#xff1a;“云原生不但可以很好的支持互联网应用&#xff0c;也在深刻影响着新的计算架构、新的智能数据…

走近科学,探究阿里闲鱼团队通过数据提升Flutter体验的真相

背景 闲鱼客户端的flutter页面已经服务上亿级用户&#xff0c;这个时候Flutter页面的用户体验尤其重要&#xff0c;完善Flutter性能稳定性监控体系&#xff0c;可以及早发现线上性能问题&#xff0c;也可以作为用户体验提升的衡量标准。那么Flutter的性能到底如何&#xff1f;…

阿里3篇技术论文入选国际顶级会议FAST2020,全球第一!

2月26日&#xff0c;存储行业顶级国际会议FAST2020&#xff08;18th USENIX Conference on File and Storage Technologies&#xff09;在美国圣克拉拉举行&#xff0c;大会公开论文名单显示&#xff0c;阿里巴巴3篇第一作者论文入选&#xff0c;是全球入选数最多的企业。 FAS…

oracle11g linux 日期格式设置

下面的过程把oracle 的日期格式设置成 yyyy-mm-dd hh24:mi:ss(1) 使用 oracle 用户登录(2) 在.bash_profile里增加以下两条环境变量export NLS_LANGamerican_america.ZHS16GBK export NLS_DATE_FORMAT"YYYY-MM-DD HH24:MI:SS" (3) 执行一下"source .bash_profil…