当前位置: 首页 > news >正文

异步servlet

我们日常使用的 SpringMVC,基本上都不是异步 Servlet,而学习 WebFlux,异步 Servlet 是基础,WebFlux。


1.什么是异步 Servlet


先来说说什么是非异步 Servlet。
在 Servlet3.0 之前,Servlet 采用 Thread-Per-Request 的方式处理 Http 请求,即每一次请求都是由某一个线程从头到尾负责处理。
如果一个请求需要进行 IO 操作,比如访问数据库、调用第三方服务接口等,那么其所对应的线程将同步地等待 IO 操作完成, 而 IO 操作是非常慢的,所以此时的线程并不能及时地释放回线程池以供后续使用,如果并发量很大的话,那肯定会造性能问题。
传统的 MVC 框架如 SpringMVC 也无法摆脱 Servlet 的桎梏,原因很简单,他们都是基于 Servlet 来实现的。如 SpringMVC 中大家所熟知的 DispatcherServlet(如果大家对于 SpringMVC 的原理不太理解,可以查看松哥之前的系列文章SpringMVC源码解读系列,20 篇干货完美收官!)。
为了解决这一问题,Servlet3.0 中引入了异步 Servlet,然后在 Servlet3.1 中又引入了非阻塞 IO 来进一步增强异步处理的性能。
在正式开整 WebFlux 之前,我们先来了解下异步 Servlet 的一些基本玩法。


2.版本关系


我们要先看看 Servlet 和 Tomcat 之间的对应关系,毕竟异步 Servlet 这种事,用错了 Tomcat 版本可能就不支持了。
下图来自 Tomcat 官网(http://tomcat.apache.org/whichversion.html):
从上图我们可以看出,Servlet3.0 对应的 Tomcat 版本是 7.0.x,Servlet3.1 对应的 Tomcat 版本是
8.0.x。
换句话说,如果我们要使用异步 Servlet,Tomcat 至少要 7.0 以上的版本;如果你还想体验一把非阻塞IO,那么 Tomcat 至少要 8.0 以上。
接下来的案例小伙伴们记得选好自己本地的 Tomcat 版本。


3.基本玩法


先来看一个大家熟悉的同步 Servlet:
@WebServlet(urlPatterns = "/sync")
这个 Servlet 大家再熟悉不过了。
前端请求到达后,我们调用 printLog 方法做一些处理,同时把 doGet 方法执行耗时打印出来。
在 printLog 中,我们先休息 3s,然后给前端返回一个字符串给前端。
前端发送请求,最终 doGet 方法中耗时 3001 毫秒。
这是我们大家熟知的同步 Servlet。在整个请求处理过程中,请求会一直占用 Servlet 线程,直到一个请求处理完毕这个线程才会被释放。
接下来我们对其稍微进行改造,使之变为一个异步 Servlet。
有人可能会说,异步有何难?直接把 printLog 方法扔到子线程里边去执行不就行了?但是这样会有另外一个问题,子线程里边没有办法通过 HttpServletResponse 直接返回数据,所以我们一定需要
Servlet 的异步支持,有了异步支持,才可以在子线程中返回数据。
我们来看改造后的代码:


public class SyncServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
doGet(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
long start = System.currentTimeMillis();
printLog(request, response);
System.out.println("总耗时:" + (System.currentTimeMillis() - start));
}
private void printLog(HttpServletRequest request, HttpServletResponse
response) throws IOException {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
response.getWriter().write("ok");
}
}
@WebServlet(urlPatterns = "/async",asyncSupported = true)
public class AsyncServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
doGet(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
long start = System.currentTimeMillis();
AsyncContext asyncContext = request.startAsync();


这里的改造主要有如下几方面:
1. @WebServlet 注解上添加 asyncSupported 属性,开启异步支持。
2. 调用 request.startAsync(); 方法开启异步上下文。
3. 通过 JDK8 中的 CompletableFuture.runAsync 方法来启动一个子线程(当然也可以自己 new 一
个子线程)。
4. 调用 printLog 方法时的 request 和 response 重新构造,直接从 asyncContext 中获取,注意,
这点是【关键】。
5. 在 printLog 方法中,方法执行完成后,调用 asyncContext.complete() 方法通知异步上下文请求
处理完毕。
经过上面的改造之后,现在的控制台打印出来的总耗时几乎可以忽略不计了。
也就是说,有了异步 Servlet 之后,后台 Servlet 的线程会被及时释放,释放之后又可以去接收新的请求,进而提高应用的并发能力。
第一次接触异步 Servlet 的小伙伴可能会有一个误解,以为用了异步 Servlet 后,前端的响应就会加快。这个怎么说呢?后台的并发能力提高了,前端的响应速度自然会提高,但是我们一两个简单的请求是很难看出这种提高的。
CompletableFuture.runAsync(() ->
printLog(asyncContext,asyncContext.getRequest(),asyncContext.getResponse()));
System.out.println("总耗时:" + (System.currentTimeMillis() - start));
}
private void printLog(AsyncContext asyncContext, ServletRequest request,
ServletResponse response){
try {
Thread.sleep(3000);
response.getWriter().write("ok");
asyncContext.complete();
} catch (InterruptedException | IOException e) {
e.printStackTrace();
}
}
}

相关文章:

异步servlet

我们日常使用的 SpringMVC,基本上都不是异步 Servlet,而学习 WebFlux,异步 Servlet 是基础,WebFlux。 1.什么是异步 Servlet 先来说说什么是非异步 Servlet。 在 Servlet3.0 之前,Servlet 采用 Thread-Per-Request 的方…...

煤矿皮带运输智能监控算法 opencv

煤矿皮带运输智能监控算法通过opencvpython深度学习算法网络模型,煤矿皮带运输智能监控算法实时监测皮带运输过程中的各种异常情况,如跑偏、撕裂、堆料异常等,一旦检测到异常情况,立即发出告警并采取相应的措施,以保障…...

Docker搭建elasticsearch+kibana测试

最近需要做大数据画像,所以先简单搭建一个eskibana学习使用,记录一下搭建过程和遇到的问题以及解决办法 1.拉取es和kibana镜像 在拉取镜像之前先搜索一下 elasticsearch发现是存在elasticsearch镜像的,我一般习惯性拉取最新镜像&#xff0c…...

QT(C++)-QTreeview节点折叠与展开

文章目录 1、前言2、QTreeview全部展开与折叠3、QTreeview某个节点展开与折叠3.1 节点折叠与展开的信号与槽3.2 槽函数的实现3.3 某个节点展开与折叠 1、前言 最近要用QT开发项目,对QT不是很熟,就根据网上的查到的知识和自己的摸索,将一些经…...

项目 - 后端技术栈转型方案

前言 某开发项目的后端技术栈比较老了,现在想换到新的技术栈上。使用更好的模式、设计思想、更合理的架构等,为未来的需求迭代做铺垫。怎么办呢?假设系统目前在线上运行着的,直接整体换的话耗时太久,且中间还有新的需…...

Oracle权限语句

授予权限:grant 权限 to 用户名; 撤销权限:revoke 权限 from 用户名; 常用: 创建用户: create user zhangsan identified by zhangsan; grant connect, resource to zhangsan; //授权zhangsan用户连接权限 grant create …...

微信小程序发布一个npm包

参考:https://developers.weixin.qq.com/miniprogram/dev/devtools/npm.html 同npm一样流程 npm install weixin_heath_apis...

Pytorch-lightning简介

Pytorch-lightning pytorch-lighting(简称pl),它其实就是一个轻量级的PyTorch库,用于高性能人工智能研究的轻量级PyTorch包装器。缩放你的模型,而不是样板。 框架核心内容 研究代码(位于LightningModule…...

【ES6】迭代器Iterator

JavaScript中的Iterator是一种特殊对象,它允许我们访问并操作对象的每一个元素。Iterator对象由具有next方法的对象创建,next方法返回一个包含两个属性的对象:value和done。value属性是当前元素的值,done属性是一个布尔值&#xf…...

火狐浏览器使用scss嵌套编写css无法识别问题

火狐浏览器使用scss嵌套编写css无法识别问题 版本: “node-sass”: “^4.14.1”, “sass-loader”: “^7.3.1”,vue版本: v2问题描述: 我的文件目录是这样的: 而在scss文件中我是这样书写的 .vue文件中 在火狐浏览器中 在谷…...

Kotlin的Lambda闭包语法

Lambda 表达式是一种在现代编程语言中常见的特性,它可以用来创建匿名函数或代码块,使得将函数作为参数传递、简化代码以及实现函数式编程范式变得更加便捷。Lambda 表达式在函数式编程语言中得到广泛应用,也在诸如 Java 8 和 Kotlin 等主流编…...

day-01 Docker

一、docker简介 Docker 是一种开源的容器化平台,它可以帮助开发人员将应用程序及其依赖项打包成一个独立的、可移植的容器,而无需担心环境差异和依赖问题。通过使用 Docker,您可以更轻松地创建、分发和运行应用程序,无论是在开发、…...

ARM开发,stm32mp157a-A7核SPI总线实验(实现数码管的显示)

1.目标: a.数码管显示相同的值 0000 1111 ......9999; b.数码管显示不同的值 1234; 2.分析m74hc595芯片内部框图; 真值表: 3.代码; ---spi.h头文件--- #ifndef __SPI_H__ #define __SPI_H__#include &quo…...

思路灰度传感器及红外传感器线序

四路红外传感器 黑线读取数据为0 白线读取数据为1 四路灰度传感器 黑线读取数据为1 白线读取数据为0...

squid服务器

目录 squid初识 安装squid代理 常用命令 主要配置文件 正向代理 环境配置 linux服务器设置 windows客户端设置 反向代理 环境配置 在web服务器配置服务 linux服务器配置 squid初识 含义:squid cache是一个流行的自由软件(GNU通用公共许可证…...

spring的后置处理器BeanPostProcessor

什么是BeanPostProcessor 是spring IOC容器给我们提供的一个扩展接口在调用初始化方法前后对bean进行额外加工,ApplicationContext会自动扫描实现了BeanPostProcessor的bean,并注册这些bean为后置处理器是bean的统一前置后置处理而不是基于某一个bean 执…...

vue、uniapp中动态添加绑定style、class 9种方法实现

9种方法介绍 直接使用静态class和style属性: 使用场景:当class和style属性是固定不变的时候,可以直接在模板中写死。优点:简单直接,没有额外的计算和逻辑。缺点:无法根据条件动态修改class和style。 使用v…...

【CicadaPlayer】seek :SeekInCache(int64_t pos)的实现

SuperMediaPlayer::SeekInCache(int64_t pos) 的实现 seek的pos就是pts值。缓冲是list,那么插入的包是按照到达的顺序插入到list的,也就是无排序的。包的pts 正常应该单调连续,即使不单调连续,缓存也不在意。seek的操作主要是先比较pos与mCurrentPos ,pos 比 mCurrentPos …...

【C/C++】x -x 的含义

1、含义 -x 的值,其实就是在x的值的基础上进行按位取反(~x)之后在增加1所得(C语言中,-x实现是用取反1实现)也就是说:x & -x x & (~x 1) 2、x 为偶数 当一个奇数 1时,表示…...

[ZenTao]源码阅读:加载自定义任务类型

www/index.php config/config.php framework/base/router.class.php tmp/model/common.php module/common/model.php framework/router.class.php...

变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析

一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...

基于FPGA的PID算法学习———实现PID比例控制算法

基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

Axios请求超时重发机制

Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式&#xff1a; 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

服务器--宝塔命令

一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行&#xff01; sudo su - 1. CentOS 系统&#xff1a; yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...

Bean 作用域有哪些?如何答出技术深度?

导语&#xff1a; Spring 面试绕不开 Bean 的作用域问题&#xff0c;这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开&#xff0c;结合典型面试题及实战场景&#xff0c;帮你厘清重点&#xff0c;打破模板式回答&#xff0c…...

【Linux】自动化构建-Make/Makefile

前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具&#xff1a;make/makfile 1.背景 在一个工程中源文件不计其数&#xff0c;其按类型、功能、模块分别放在若干个目录中&#xff0c;mak…...

Vue3中的computer和watch

computed的写法 在页面中 <div>{{ calcNumber }}</div>script中 写法1 常用 import { computed, ref } from vue; let price ref(100);const priceAdd () > { //函数方法 price 1price.value ; }//计算属性 let calcNumber computed(() > {return ${p…...