servlet3异步_Servlet 3的异步Servlet功能

servlet3异步

在深入了解什么是异步Servlet之前,让我们尝试了解为什么需要它。 假设我们有一个Servlet,处理时间很长,如下所示。

LongRunningServlet.java

package com.journaldev.servlet;import java.io.IOException;
import java.io.PrintWriter;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@WebServlet("/LongRunningServlet")
public class LongRunningServlet extends HttpServlet {private static final long serialVersionUID = 1L;protected void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {long startTime = System.currentTimeMillis();System.out.println("LongRunningServlet Start::Name="+ Thread.currentThread().getName() + "::ID="+ Thread.currentThread().getId());String time = request.getParameter("time");int secs = Integer.valueOf(time);// max 10 secondsif (secs > 10000)secs = 10000;longProcessing(secs);PrintWriter out = response.getWriter();long endTime = System.currentTimeMillis();out.write("Processing done for " + secs + " milliseconds!!");System.out.println("LongRunningServlet Start::Name="+ Thread.currentThread().getName() + "::ID="+ Thread.currentThread().getId() + "::Time Taken="+ (endTime - startTime) + " ms.");}private void longProcessing(int secs) {// wait for given time before finishingtry {Thread.sleep(secs);} catch (InterruptedException e) {e.printStackTrace();}}}

如果我们通过浏览器在URL上方为http://localhost:8080/AsyncServletExample/LongRunningServlet?time=8000 servlet上方收到响应,则响应为“处理完成8000毫秒!” 8秒后。 现在,如果您查看服务器日志,将得到以下日志:

LongRunningServlet Start::Name=http-bio-8080-exec-34::ID=103
LongRunningServlet Start::Name=http-bio-8080-exec-34::ID=103::Time Taken=8002 ms.

因此,尽管大多数处理与Servlet请求或响应无关,但我们的Servlet线程运行了大约8+秒。

这可能导致线程饥饿 -由于在所有处理完成之前我们的servlet线程被阻塞,因此如果服务器收到大量要处理的请求,它将达到最大servlet线程限制,并且进一步的请求将出现Connection Refused错误。

在Servlet 3.0之前,有针对这些长时间运行的线程的特定于容器的解决方案,我们可以生成单独的工作线程来执行繁重的任务,然后将响应返回给客户端。 启动工作线程后,Servlet线程返回到Servlet池。 Tomcat的Comet,WebLogic的FutureResponseServlet和WebSphere的异步请求分派器是异步处理实现的一些示例。

特定于容器的解决方案的问题在于,在不更改应用程序代码的情况下,我们无法移至其他servlet容器,这就是为什么在Servlet 3.0中添加了Async Servlet支持以为Servlet中的异步处理提供标准方式的原因。

异步Servlet实现

让我们看一下实现异步servlet的步骤,然后为上述示例提供异步支持的servlet。

  1. 首先,我们要提供异步支持的servlet应该具有@WebServlet 批注 ,其asyncSupported值为true
  2. 由于实际工作将委托给另一个线程,因此我们应该有一个线程池实现。 我们可以使用Executors框架创建线程池,并使用servlet上下文侦听器来启动线程池。
  3. 我们需要通过ServletRequest.startAsync()方法获取AsyncContext的实例。 AsyncContext提供了获取ServletRequest和ServletResponse对象引用的方法。 它还提供了使用dispatch()方法将请求转发到另一个资源的方法。
  4. 我们应该有一个Runnable实现 ,在这里我们将进行繁重的处理,然后使用AsyncContext对象将请求分派到另一个资源,或者使用ServletResponse对象写入响应。 处理完成后,我们应调用AsyncContext.complete()方法以使容器知道异步处理已完成。
  5. 我们可以将AsyncListener实现添加到AsyncContext对象中以实现回调方法–我们可以使用它为异步线程处理过程中发生错误或超时的情况提供对客户端的错误响应。 我们还可以在此处进行一些清理活动。

一旦我们完成了用于异步Servlet示例的项目,它将如下图所示。

异步Servlet示例

在Servlet上下文侦听器中初始化辅助线程池

AppContextListener.java

package com.journaldev.servlet.async;import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;@WebListener
public class AppContextListener implements ServletContextListener {public void contextInitialized(ServletContextEvent servletContextEvent) {// create the thread poolThreadPoolExecutor executor = new ThreadPoolExecutor(100, 200, 50000L,TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(100));servletContextEvent.getServletContext().setAttribute("executor",executor);}public void contextDestroyed(ServletContextEvent servletContextEvent) {ThreadPoolExecutor executor = (ThreadPoolExecutor) servletContextEvent.getServletContext().getAttribute("executor");executor.shutdown();}}

该实现非常简单,如果您不熟悉Executors框架,请阅读Thread Pool Executor

有关监听器的更多详细信息,请阅读Servlet Listener Tutorial

工作线程实现

AsyncRequestProcessor.java

package com.journaldev.servlet.async;import java.io.IOException;
import java.io.PrintWriter;import javax.servlet.AsyncContext;public class AsyncRequestProcessor implements Runnable {private AsyncContext asyncContext;private int secs;public AsyncRequestProcessor() {}public AsyncRequestProcessor(AsyncContext asyncCtx, int secs) {this.asyncContext = asyncCtx;this.secs = secs;}@Overridepublic void run() {System.out.println("Async Supported? "+ asyncContext.getRequest().isAsyncSupported());longProcessing(secs);try {PrintWriter out = asyncContext.getResponse().getWriter();out.write("Processing done for " + secs + " milliseconds!!");} catch (IOException e) {e.printStackTrace();}//complete the processingasyncContext.complete();}private void longProcessing(int secs) {// wait for given time before finishingtry {Thread.sleep(secs);} catch (InterruptedException e) {e.printStackTrace();}}
}

请注意,AsyncContext的用法及其在获取请求和响应对象,然后通过complete()方法调用完成异步处理的用法。

AsyncListener实现

AppAsyncListener.java

package com.journaldev.servlet.async;import java.io.IOException;
import java.io.PrintWriter;import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebListener;@WebListener
public class AppAsyncListener implements AsyncListener {@Overridepublic void onComplete(AsyncEvent asyncEvent) throws IOException {System.out.println("AppAsyncListener onComplete");// we can do resource cleanup activity here}@Overridepublic void onError(AsyncEvent asyncEvent) throws IOException {System.out.println("AppAsyncListener onError");//we can return error response to client}@Overridepublic void onStartAsync(AsyncEvent asyncEvent) throws IOException {System.out.println("AppAsyncListener onStartAsync");//we can log the event here}@Overridepublic void onTimeout(AsyncEvent asyncEvent) throws IOException {System.out.println("AppAsyncListener onTimeout");//we can send appropriate response to clientServletResponse response = asyncEvent.getAsyncContext().getResponse();PrintWriter out = response.getWriter();out.write("TimeOut Error in Processing");}}

注意onTimeout()方法的实现,在该方法中,我们向客户端发送超时响应。

这是我们异步servlet的实现,请注意使用AsyncContext和ThreadPoolExecutor进行处理。

AsyncLongRunningServlet.java

package com.journaldev.servlet.async;import java.io.IOException;
import java.util.concurrent.ThreadPoolExecutor;import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@WebServlet(urlPatterns = "/AsyncLongRunningServlet", asyncSupported = true)
public class AsyncLongRunningServlet extends HttpServlet {private static final long serialVersionUID = 1L;protected void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {long startTime = System.currentTimeMillis();System.out.println("AsyncLongRunningServlet Start::Name="+ Thread.currentThread().getName() + "::ID="+ Thread.currentThread().getId());request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true);String time = request.getParameter("time");int secs = Integer.valueOf(time);// max 10 secondsif (secs > 10000)secs = 10000;AsyncContext asyncCtx = request.startAsync();asyncCtx.addListener(new AppAsyncListener());asyncCtx.setTimeout(9000);ThreadPoolExecutor executor = (ThreadPoolExecutor) request.getServletContext().getAttribute("executor");executor.execute(new AsyncRequestProcessor(asyncCtx, secs));long endTime = System.currentTimeMillis();System.out.println("AsyncLongRunningServlet End::Name="+ Thread.currentThread().getName() + "::ID="+ Thread.currentThread().getId() + "::Time Taken="+ (endTime - startTime) + " ms.");}}

运行异步Servlet

现在,当我们在servlet上运行,URL为http://localhost:8080/AsyncServletExample/AsyncLongRunningServlet?time=8000我们得到的响应和日志如下:

AsyncLongRunningServlet Start::Name=http-bio-8080-exec-50::ID=124
AsyncLongRunningServlet End::Name=http-bio-8080-exec-50::ID=124::Time Taken=1 ms.
Async Supported? true
AppAsyncListener onComplete

如果我们将时间设置为9999,则会发生超时,并在客户端以“处理中的超时错误”和日志形式获得响应:

AsyncLongRunningServlet Start::Name=http-bio-8080-exec-44::ID=117
AsyncLongRunningServlet End::Name=http-bio-8080-exec-44::ID=117::Time Taken=1 ms.
Async Supported? true
AppAsyncListener onTimeout
AppAsyncListener onError
AppAsyncListener onComplete
Exception in thread "pool-5-thread-6" java.lang.IllegalStateException: The request associated with the AsyncContext has already completed processing.at org.apache.catalina.core.AsyncContextImpl.check(AsyncContextImpl.java:439)at org.apache.catalina.core.AsyncContextImpl.getResponse(AsyncContextImpl.java:197)at com.journaldev.servlet.async.AsyncRequestProcessor.run(AsyncRequestProcessor.java:27)at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)at java.lang.Thread.run(Thread.java:680)

注意,servlet线程快速完成了执行,所有主要的处理工作都在其他线程中进行。

这就是异步Servlet的全部,希望您喜欢它。

  • 下载AsyncServletExample项目

参考: 开发者食谱博客上来自JCG合作伙伴 Pankaj Kumar 的Servlet 3异步Servlet功能 。

翻译自: https://www.javacodegeeks.com/2013/08/async-servlet-feature-of-servlet-3.html

servlet3异步

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

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

相关文章

计算机二级web题目(7.2)--基本操作题1

前些天发现了一个巨牛的人工智能学习电子书&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;无广告&#xff0c;忍不住分享一下给大家。&#xff08;点击跳转人工智能学习资料&#xff09; 1、在考生文件夫下的Web1目录中&#xff0c;存有1.htm和label2.htm文件&#xff…

计算机二级web题目(7.3)--简单应用题1

说明&#xff1a;如有不清楚的地方&#xff0c;可以评论区留言&#xff0c;及时回复。 1、在考生文件夹下的Web3目录中&#xff0c;存有3.htm文件&#xff0c;该文件不完整&#xff0c;请在标有********Found******字符串的注释行下一语句的下划线处填入正确内容&#xff0c;然…

使用Spring Security 5.0和OIDC轻松构建身份验证

“我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕&#xff1f; 尝试使用Okta API进行托管身份验证&#xff0c;授权和多因素身份验证。 Spring Security不仅是一个功能强大且可高度自定义的身份验证和访问控制框架&#xf…

计算机二级web题目(7.4)--综合应用题1

说明&#xff1a;如有不清楚的地方&#xff0c;可以评论留言&#xff0c;及时回复。 1、在考生文件夹下的Web5目录中&#xff0c;存有5.htm文件&#xff0c;该文件不完整&#xff0c;请在标有 *********Foun********字符串的往释行 下一-语句的下划线处填入正确内容&#xff0c…

(1.2)HarmonyOS鸿蒙config.json

跟应用相关的所有信息&#xff0c;都会在config.json文件中进行配置。 项目的配置&#xff08;app&#xff09; 比如&#xff1a;厂商信息&#xff0c;项目的版本等 应用在设备上的配置信息&#xff08;deviceConfig&#xff09; 比如&#xff1a;应用运行时进程名&#xff0c…

Arquillian变色龙。 简化您的Arquillian测试

Arquillian Chameleon的诞生是为了简化Arquillian测试的配置。 我很自豪地宣布&#xff0c;使用1.0.0.CR2版本&#xff0c;我们不仅简化了Arquillian测试的配置方式&#xff0c;而且简化了编写方式。 在此新版本中&#xff0c;添加了三个新的简化&#xff1a; 您只需要使用1个…

为什么要学习鸿蒙,HarmonyOS不只是操作系统

前些天发现了十分不错的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;没有广告&#xff0c;分享给大家&#xff0c;大家可以自行看看。&#xff08;点击跳转人工智能学习资料&#xff09; 前言 对于IT行业&#xff0c;头部力量或者已经形成生态的东西…

mysql 视图树查询_TreeView (树视图)遍历数据库的方法

多数从事数据库编程人员都经历过&#xff0c;对新接触的数据库技术无论是低版本Foxbase、Access97-2000还是支持网络环境高版本的Sql Server2000和 Oracel等系统&#xff0c;都经过一个循循渐进、吃苦耐劳学习过程&#xff0c;达到知识技术从量变到质变的过程&#xff0c;才能把…

(1.3)HarmonyOS鸿蒙启动程序运行流程

程序启动运行流程&#xff1a; ①解析config.json文件 ②初始化 ③获取入口Ability的全类名&#xff08;config.json里的module里的mainAbility&#xff09; ④找到Ability并运行 ⑤运行Ability中的子界面 ⑥加载xml文件&#xff0c;展示内容&#xff08;xml在resources里面&am…

arraylist内存溢出_ArrayList使用内存映射文件

arraylist内存溢出介绍 内存中的计算由于负担得起的硬件而开始兴起&#xff0c;大多数数据保留在RAM中以满足延迟和吞吐量的目标&#xff0c;但是将数据保留在RAM中会增加垃圾收集器的开销&#xff0c;尤其是在您不预先分配内存的情况下。 因此&#xff0c;有效地我们需要一种无…

【vtkWidgetRepresentation】第十八期 vtkHoverWidget

很高兴在雪易的CSDN遇见你 VTK技术爱好者 QQ:870202403 前言 本文分享vtkHoverWidget,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步! 你的点赞就是我的动力(^U^)ノ~YO 1. vtkHoverWidget vtkHoverWidget用于在呈现窗口中…

Java面向对象(2)--类的成员属性

基本格式&#xff1a;修饰符 数据类型 属性名 初始化值 ; 说明1: 修饰符 ①常用的权限修饰符&#xff1a;private、缺省、protected、public ②其他修饰符&#xff1a;static、final 说明2&#xff1a;数据类型 任何基本数据类型和任何引用数据类型。 说明3&#xff1a;属性…

使用Spring Session和JDBC DataStore进行会话管理

在Web应用程序中&#xff0c;用户会话管理对于管理用户状态至关重要。 在本文中&#xff0c;我们将学习在集群环境中管理用户会话所遵循的方法&#xff0c;以及如何使用Spring Session以更加简单和可扩展的方式实现它。 通常在生产环境中&#xff0c;我们将有多个服务器节点&a…

Java面向对象(3)--类的成员方法

基本格式&#xff1a; 修饰符 返回值类型 方法名&#xff08;参数类型 形参1, 参数类型 形参2, …&#xff09;&#xff5b;方法体程序代码;return 返回值; &#xff5d;修饰符&#xff1a;public,缺省,private, protected等 返回值类型&#xff1a; ①没有返回值&#xff1a…

python统计图像直方图_计算机视觉7-像素点直方图统计、掩膜图像

1.灰度图的直方图(1)调用库import cv2import matplotlib.pyplot as pltimport numpy as np #创建掩膜时需要(2)绘图-方法1imgcv2.imread(F:cat.jpg,0)plt.hist(img.ravel(),256,[0,256])plt.show()plt.hist是一个画直方图的命令&#xff1b;img.ravel()可以将图片转化成一维数组…

计算机二级web题目(8.1)--综合选择题2

前些天发现了一个巨牛的人工智能学习电子书&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;无广告&#xff0c;忍不住分享一下给大家。&#xff08;点击跳转人工智能学习资料&#xff09; 1、一个栈的初始状态为空。现将元素1、2、3、4、5、A、B、C、D、E依次入栈,然后再…

Java面向对象(4)--封装和隐藏

Java中通过将数据声明为私有的(private)&#xff0c;再提供公共的&#xff08;public&#xff09;方法:获取getXxx()和设置setXxx()实现对该属性的操作&#xff0c;以实现下述目的&#xff1a; ①隐藏一个类中不需要对外提供的实现细节。 ②使用者只能通过事先定制好的方法来访…

跑来跑去:假人与AWS Lambda的第一次接触

一切始于埃及人在一个木框上滑动几块大理石以简单的算术使其大脑放松。 或许是希腊人发明了Antikythera机制来追踪行星的运动至每千年2度的精度 。 无论哪种方式&#xff0c;计算都已经走了很长一段路&#xff1a;查尔斯巴贝奇的分析引擎 &#xff0c;艾伦图灵的Enigma-breaker…

(2.1)HarmonyOS鸿蒙Ability创建,XML和Java页面布局UI

鸿蒙UI中&#xff0c;提供了两种编写布局的方式&#xff1a; ①在XML中声明UI布局 ②在Ability代码中直接通过Java创建布局 这两种方式创建出的布局没有本质差别&#xff0c;但是XML方式较为方便简单。 在XML文件中布局 与HTMLCSS的前端布局类似&#xff0c;通过使用不同类型的…

使用Azure Blob存储托管Maven工件

如果您使用Microsoft Azure并且将Java用于项目&#xff0c;则Azure Blob存储是托管团队工件的理想场所。 它很容易设置&#xff0c;而且很便宜。 如果您对它们的功能不特别感兴趣&#xff0c;那么它比设置现有存储库选项&#xff08;jfrog&#xff0c;nexus&#xff0c;archiv…