博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
异步Servlet
阅读量:5929 次
发布时间:2019-06-19

本文共 5518 字,大约阅读时间需要 18 分钟。

异步Servlet

有的时候servlet在相应报文之前会有一些耗时操作,比如JDBC的操作,或者等待另一个远程Web的响应,同步Servlet中等待阻塞会导致Web容器整体的处理能力低下。对于这种情况可使用servlet异步处理方式,把比较耗时的操作可以放置到另外一个线程中进行处理,此过程保留连接的请求和响应对象,在处理完成之后可以把处理的结果通知到客户端。

同步Servlet

如图所示,Tomcat的客户端请求由管道处理最后会通过Wrapper容器的管道,这时它会调Servlet实例的service方法进行逻辑处理,处理完后响应客户端,整个处理由Tomcat的Executor线程池的线程处理。

![img](file:///var/folders/74/8gxv5r0j3xvflks6fxth63540000gn/T/WizNote/de95c2ac-493a-4c0b-ac87-f45447bb6345/index_files/73010586.png)

缺点:遇见处理逻辑耗时较长的任务会长时间的占用tomcat的处理线程,影响tomcat的整体处理能力。特别是当你的线程数有限比如只有5个,同时遇见5个耗时100ms的请求,那么在这100ms内的其它请求都会失败,严重影响的服务的吞吐量和稳定性。

优点:实现逻辑简单易懂,对于大量的耗时短的任务性能好。

异步Servlet

异步Servlet是在3.0版本引入的,客户端请求到来,然后通过管道最后进入到Wrapper容器的管道,调用Servlet实例的service后,创建一个异步上下文将耗时的逻辑操作封装起来,交给用户自己定义的线程池,这时Tomcat的处理线程就能马上回到Executor线程池,而不用等待耗时的操作完成才让出线程,从而提升了Tomcat的整体处理能力。

![img](file:///var/folders/74/8gxv5r0j3xvflks6fxth63540000gn/T/WizNote/de95c2ac-493a-4c0b-ac87-f45447bb6345/index_files/73445233.png)

一个?

初始化线程池

@WebListener  public class AppContextListener implements ServletContextListener {         public void contextInitialized(ServletContextEvent servletContextEvent) {             // create the thread pool          ThreadPoolExecutor executor = new ThreadPoolExecutor(100, 200, 50000L,                  TimeUnit.MILLISECONDS, new ArrayBlockingQueue
(100)); servletContextEvent.getServletContext().setAttribute("executor", executor); } public void contextDestroyed(ServletContextEvent servletContextEvent) { ThreadPoolExecutor executor = (ThreadPoolExecutor) servletContextEvent .getServletContext().getAttribute("executor"); executor.shutdown(); } }复制代码

编写一个监听器,监听异步任务生命周期中的一些动作。

public class AppAsyncListener implements AsyncListener {         @Override      public void onComplete(AsyncEvent asyncEvent) throws IOException {          System.out.println("AppAsyncListener onComplete");          // we can do resource cleanup activity here      }         @Override      public void onError(AsyncEvent asyncEvent) throws IOException {          System.out.println("AppAsyncListener onError");          //we can return error response to client      }         @Override      public void onStartAsync(AsyncEvent asyncEvent) throws IOException {          System.out.println("AppAsyncListener onStartAsync");          //we can log the event here      }         @Override      public void onTimeout(AsyncEvent asyncEvent) throws IOException {          System.out.println("AppAsyncListener onTimeout");          //we can send appropriate response to client          ServletResponse response = asyncEvent.getAsyncContext().getResponse();          PrintWriter out = response.getWriter();          out.write("TimeOut Error in Processing");      }     } 复制代码

具体的业务逻辑放在一个Runable的实现类中

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;      }         @Override      public 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 processing          asyncContext.complete();      }         private void longProcessing(int secs) {          // wait for given time before finishing          try {              Thread.sleep(secs);          } catch (InterruptedException e) {              e.printStackTrace();          }      }  }  复制代码

最后,Async Servlet 实现

@WebServlet(urlPatterns = "/AsyncLongRunningServlet", asyncSupported = true)public class AsyncLongRunningServlet extends HttpServlet {    private static final long serialVersionUID = 1L;    @Override    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 seconds        if (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));        long endTime = System.currentTimeMillis();        System.out.println("AsyncLongRunningServlet End::Name="                + Thread.currentThread().getName() + "::ID="                + Thread.currentThread().getId() + "::Time Taken="                + (endTime - startTime) + " ms.");    }}复制代码

PS:在 SpringBootApplication 上使用@ServletComponentScan 注解后,Servlet、Filter、Listener 可以直接通过 @WebServlet、@WebFilter、@WebListener 注解自动注册,无需其他代码。

转载于:https://juejin.im/post/5a3d02cd5188252b145b3ea0

你可能感兴趣的文章
java 下载文件
查看>>
win2K/win2003终端服务器超出最大允许连接数解决之道
查看>>
GNU make manual 翻译(二十六)
查看>>
linux 中 sed 用法
查看>>
GNU make manual 翻译(八十三)
查看>>
iReport 编辑的报表,在jsp中导出到PDF的代码
查看>>
组织行为学对项目管理的意义(1)
查看>>
GridView 中点击行操作显示基本信息,类似查看的功能。
查看>>
Fred Wilson谈教育技术创业
查看>>
使用Trace.axd 调试ASP.NET
查看>>
工作要求
查看>>
ASP.NET:EXCEL找不到文件、权限不够之综合解决方案
查看>>
Panels 使用教程
查看>>
C 语言中堆栈的理解
查看>>
【C++学习】函数对象和Lambda表达式
查看>>
【转载】关于MVC4.0 WebAPI上传图片重命名以及图文结合
查看>>
Unicode下CString与char *相互转换
查看>>
CheckListBox怎样得到多选值?
查看>>
Java中基本数据类型和包装数据类型在Hibernate中使用
查看>>
Python入门指南
查看>>