异步servlet的不演戏异步 [英] Asynchronous servlet not acting asynchronously

查看:309
本文介绍了异步servlet的不演戏异步的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个servlet,需要一个请求,并写了一个很长的响应。响应是在使用了Thread.sleep(1000)以模拟长期运行动作的循环。我试图建立一个异步请求在这里,如图code。但它不工作。当调用多个请求到Servlet,他们都执行连续,不能在同一时间。我究竟做错了什么?

和我虽然servlet应该是螺纹 - 每个请求服务器导致执行一个新的线程(或重用一个来自池)容器

 封装测试;进口java.io.IOException异常;
进口的java.io.PrintWriter;
进口javax.servlet.ServletException;进口javax.servlet.http.HttpServlet;
进口javax.servlet.http.HttpServletRequest;
进口javax.servlet.http.HttpServletResponse;进口javax.servlet.AsyncContext;进口javax.servlet.annotation.WebServlet;@WebServlet(URL模式= {/测试},asyncSupported = TRUE)
公共类TestServ延伸的HttpServlet {    @覆盖
    公共无效的doGet(HttpServletRequest的RQ,HttpServletResponse的RS){        rs.setContentType(text / plain的);
        rs.setHeader(访问控制允许原产地,*);
        AsyncContext ASY = rq.startAsync(RQ,RS);
        asy.start(新客户端(ASY));
    }
    @覆盖
    公共字符串getServletInfo方法(){
        返回简短说明;
    }
}类客户端实现Runnable {    私人INT计数器= 0;
    私人AsyncContext ASY;    客户端(AsyncContext ASY){
        this.asy = ASY;
    }    @覆盖
    公共无效的run(){
        //此处运行长期任​​务
        尝试{
            PrintWriter的OUT = asy.getResponse()的getWriter()。
            而(计数器小于5){                通过out.println(计数器++ + 1);
                视频下载(1000);            }        }赶上(例外前){        } {最后
            asy.complete();
        }
    }
}


解决方案

使用方法 ExecutorService.execute()产卵一些任务在后台线程。

执行步骤:


  • 从阅读中的web.xml servlet初始化一些初始化参数()方法,如超时和threadpoolsize

    • 超时参数是用来设置异步线程超时

    • threadpoolsize用于创建异步线程池


  • 获取AsyncContext通过调用HTTP request.startAsync()中的doGet()或doPost()方法

  • AsyncContext的设置超时

  • 连接监听器,这个AsyncContext的生命周期事件,如的onComplete(),onTimeout(),onerror的(),onStartAsync响应()

  • 呼叫ExecutorService.execute()来派生一些任务在后台线程

试试这个样本code。它可以帮助你。

AsyncServletTaskProcessor:

 进口java.io.IOException异常;进口javax.servlet.AsyncContext;
进口javax.servlet.ServletException;公共接口AsyncServletTaskProcessor ​​{    无效的过程(AsyncContext CTX)抛出IOException异常,ServletException异常;
}

TestServ:

 进口java.io.IOException异常;
进口java.util.concurrent.ExecutorService中;
进口java.util.concurrent.Executors;进口javax.servlet.AsyncContext;
进口javax.servlet.ServletException;
进口javax.servlet.annotation.WebServlet;
进口javax.servlet.http.HttpServlet;
进口javax.servlet.http.HttpServletRequest;
进口javax.servlet.http.HttpServletResponse;@WebServlet(URL模式= {/测试},asyncSupported = TRUE)
公共类TestServ延伸的HttpServlet实现AsyncServletTaskProcessor ​​{    / **这位经理。 * /
    私人的ExecutorService EXEC;    公众诠释CALLBACK_TIMEOUT;    公共无效的init()抛出了ServletException {
        //读取回调超时形式的web.xml的初始化参数
        CALLBACK_TIMEOUT =的Integer.parseInt(的getInitParameter(超时));
        //读取线程池大小形态web.xml中作为初始化参数
        INT大小=的Integer.parseInt(的getInitParameter(threadpoolsize));
        EXEC = Executors.newFixedThreadPool(大小);    }    @覆盖
    公共无效的doGet(HttpServletRequest的RQ,HttpServletResponse的RS){        rs.setContentType(text / plain的);
        rs.setHeader(访问控制允许原产地,*);        // AsyncContext ASY = rq.startAsync(RQ,RS);
        //asy.start(new客户端(ASY));        最终AsyncContext ASY = rq.startAsync();        //设置超时
        asy.setTimeout(CALLBACK_TIMEOUT);        //连接监听器,这个AsyncContext的生命周期事件作出回应
        asy.addListener(新AsyncListenerImpl(ASY));        //产卵一些任务在后台线程
        exec.execute(新AsyncServletTaskRunner(ASY,本));
    }    @覆盖
    公共字符串getServletInfo方法(){
        返回简短说明;
    }    @覆盖
    公共无效过程(AsyncContext CTX)抛出IOException异常,ServletException异常{
       //做任何你想做的事情,因为每个线程的过程
    }
}

AsyncServletTaskRunner:

 进口javax.servlet.AsyncContext;公共类AsyncServletTaskRunner实现Runnable {    / **环磷酰胺。 * /
    私人AsyncContext CTX;    / **处理器。 * /
    私人AsyncServletTaskProcessor处理器;    公共AsyncServletTaskRunner(){
        超();
    }    公共AsyncServletTaskRunner(AsyncContext CTX,AsyncServletTaskProcessor处理器){
        this.ctx = CTX;
        this.processor ​​=处理器;
    }    @覆盖
    公共无效的run(){        尝试{
            processor.process(CTX);
        }赶上(例外五){
            尝试{
                //重定向到错误页面,或做任何需要
            }赶上(例外E1){
                e1.printStackTrace();
            }
        } {最后
            ctx.complete();
        }
    }    公共AsyncContext getCtx(){
        返回CTX;
    }    公共无效setCtx(AsyncContext CTX){
        this.ctx = CTX;
    }}

AsyncListenerImpl:

 进口java.io.IOException异常;进口javax.servlet.AsyncContext;
进口javax.servlet.AsyncEvent;
进口javax.servlet.AsyncListener;公共类AsyncListenerImpl实现AsyncListener {    / **环磷酰胺。 * /
    私人AsyncContext CTX;    公共AsyncListenerImpl(){
        超();
    }    公共AsyncListenerImpl(AsyncContext CTX){
        this.ctx = CTX;
    }    @覆盖
    公共无效的onComplete(AsyncEvent事件)抛出IOException
        / **完成()已经呼吁异步上下文无关* /
    }    @覆盖
    公共无效onTimeout(AsyncEvent事件)抛出IOException
        / **超时发生在异步任务......处理它* /
        尝试{
            //重定向到错误页面,或做任何需要
        }赶上(例外E1){
            e1.printStackTrace();
        } {最后
            ctx.complete();
        }
    }    @覆盖
    公共无效的onError(AsyncEvent事件)抛出IOException
        / **这不会被调用 - 错误发生在异步任务......处理它* /
        尝试{
            //重定向到错误页面,或做任何需要
        }赶上(例外E1){
            e1.printStackTrace();
        } {最后
            ctx.complete();
        }
    }    @覆盖
    公共无效onStartAsync(AsyncEvent事件)抛出IOException
        / **异步方面已经开始,无关* /
    }}

I have a servlet that takes a request and writes a long response. The response is in a loop that uses Thread.sleep(1000) to simulate a long running operation. I am trying to setup an asynchronous request here, as shown in code. But it is not working. When i invoke several requests to the servlet, they all execute consecutively, not at the same time. What am i doing wrong?

And i though servlets are supposed to be threaded - each request to server causes the container to execute a new thread (or reuse one from the pool).

package test;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import javax.servlet.AsyncContext;

import javax.servlet.annotation.WebServlet;

@WebServlet(urlPatterns={"/test"}, asyncSupported=true)
public class TestServ extends HttpServlet {

    @Override
    public void doGet(HttpServletRequest rq, HttpServletResponse rs){

        rs.setContentType("text/plain");
        rs.setHeader("Access-Control-Allow-Origin", "*");


        AsyncContext asy = rq.startAsync(rq, rs);
        asy.start(new Client(asy));
    }


    @Override
    public String getServletInfo() {
        return "Short description";
    }
}

class Client implements Runnable {

    private int counter = 0;
    private AsyncContext asy;

    Client(AsyncContext asy) {
        this.asy = asy;
    }

    @Override
    public void run() {
        //run long task here
        try {
            PrintWriter out = asy.getResponse().getWriter();
            while (counter < 5) {

                out.println(counter++ + 1);
                Thread.sleep(1000);

            }

        } catch (Exception ex) {

        } finally{
            asy.complete();
        }
    }
}

解决方案

Use method ExecutorService.execute() to spawn some task in a background thread.

Steps to follow:

  • Read some init parameters from web.xml in servlet init() method such as timeout and threadpoolsize
    • timeout parameter is used to set the timeout of Async thread
    • threadpoolsize is used to create a pool of Async threads
  • Get AsyncContext by calling HTTP request.startAsync() in doGet() or doPost() method
  • Set timeout of AsyncContext
  • Attach listener to respond to lifecycle events of this AsyncContext such as onComplete(), onTimeout(), onError(), onStartAsync()
  • Call ExecutorService.execute() to spawn some task in a background thread

Try this sample code. It might help you.

AsyncServletTaskProcessor:

import java.io.IOException;

import javax.servlet.AsyncContext;
import javax.servlet.ServletException;

public interface AsyncServletTaskProcessor {

    void process(AsyncContext ctx) throws IOException, ServletException;
}

TestServ:

import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

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 = { "/test" }, asyncSupported = true)
public class TestServ extends HttpServlet  implements AsyncServletTaskProcessor{

    /** The exec. */
    private ExecutorService exec;

    public int CALLBACK_TIMEOUT;

    public void init() throws ServletException {
        // read callback timeout form web.xml as init parameter
        CALLBACK_TIMEOUT = Integer.parseInt(getInitParameter("timeout"));
        // read thread pool size form web.xml as init parameter
        int size = Integer.parseInt(getInitParameter("threadpoolsize"));
        exec = Executors.newFixedThreadPool(size);

    }

    @Override
    public void doGet(HttpServletRequest rq, HttpServletResponse rs) {

        rs.setContentType("text/plain");
        rs.setHeader("Access-Control-Allow-Origin", "*");

        //AsyncContext asy = rq.startAsync(rq, rs);
        //asy.start(new Client(asy));

        final AsyncContext asy = rq.startAsync();

        // set the timeout
        asy.setTimeout(CALLBACK_TIMEOUT);

        // attach listener to respond to lifecycle events of this AsyncContext
        asy.addListener(new AsyncListenerImpl(asy));

        // spawn some task in a background thread
        exec.execute(new AsyncServletTaskRunner(asy, this));
    }

    @Override
    public String getServletInfo() {
        return "Short description";
    }

    @Override
    public void process(AsyncContext ctx) throws IOException, ServletException {
       //do whatever you want to do as process of each thread
    }
}

AsyncServletTaskRunner:

import javax.servlet.AsyncContext;

public class AsyncServletTaskRunner implements Runnable {

    /** The ctx. */
    private AsyncContext ctx;

    /** The processor. */
    private AsyncServletTaskProcessor processor;

    public AsyncServletTaskRunner() {
        super();
    }

    public AsyncServletTaskRunner(AsyncContext ctx, AsyncServletTaskProcessor processor) {
        this.ctx = ctx;
        this.processor = processor;
    }

    @Override
    public void run() {

        try {
            processor.process(ctx);
        } catch (Exception e) {
            try {
                // redirect to error page or do whatever is needed
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        } finally {
            ctx.complete();
        }
    }

    public AsyncContext getCtx() {
        return ctx;
    }

    public void setCtx(AsyncContext ctx) {
        this.ctx = ctx;
    }

}

AsyncListenerImpl:

import java.io.IOException;

import javax.servlet.AsyncContext;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;

public class AsyncListenerImpl implements AsyncListener {

    /** The ctx. */
    private AsyncContext ctx;

    public AsyncListenerImpl() {
        super();
    }

    public AsyncListenerImpl(AsyncContext ctx) {
        this.ctx = ctx;
    }

    @Override
    public void onComplete(AsyncEvent event) throws IOException {
        /** complete() has already been called on the async context, nothing to do */
    }

    @Override
    public void onTimeout(AsyncEvent event) throws IOException {
        /** timeout has occured in async task... handle it */
        try {
            // redirect to error page or do whatever is needed
        } catch (Exception e1) {
            e1.printStackTrace();
        } finally {
            ctx.complete();
        }
    }

    @Override
    public void onError(AsyncEvent event) throws IOException {
        /** THIS NEVER GETS CALLED - error has occured in async task... handle it */
        try {
            // redirect to error page or do whatever is needed
        } catch (Exception e1) {
            e1.printStackTrace();
        } finally {
            ctx.complete();
        }
    }

    @Override
    public void onStartAsync(AsyncEvent event) throws IOException {
        /** async context has started, nothing to do */
    }

}

这篇关于异步servlet的不演戏异步的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆