Java 响应何时在异步servlet中传递给客户端?

Java 响应何时在异步servlet中传递给客户端?,java,multithreading,servlets,asynchronous,Java,Multithreading,Servlets,Asynchronous,我在理解异步servlet如何工作以及servlet如何向客户端发送响应方面遇到了问题。 我想做的是通过ajax将视频上传到servlet。我认为使用异步servlet,我将在浏览器中立即获得响应,然后在另一个线程中完成长任务 在为文件进程编写任何代码之前,我在这里发布了我的初始代码,只是一个测试异步性的初始servlet @WebServlet(name = "VideoUploader", urlPatterns = {"/VideoUploader"}, asyncSupport

我在理解异步servlet如何工作以及servlet如何向客户端发送响应方面遇到了问题。
我想做的是通过ajax将视频上传到servlet。我认为使用异步servlet,我将在浏览器中立即获得响应,然后在另一个线程中完成长任务

在为文件进程编写任何代码之前,我在这里发布了我的初始代码,只是一个测试异步性的初始servlet

@WebServlet(name = "VideoUploader", urlPatterns = {"/VideoUploader"}, 
    asyncSupported = true)  

@MultipartConfig
public class VideoUploader extends HttpServlet {

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    doPost(request, response);
}

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {

    final PrintWriter pw = response.getWriter();

    final AsyncContext ac = request.startAsync();
    ac.setTimeout(80000);

    ac.addListener(new AsyncListener() {
        @Override
        public void onComplete(AsyncEvent event) throws IOException {
            System.out.println("On complete");
        }

        @Override
        public void onTimeout(AsyncEvent event) throws IOException {
            System.out.println("On timeout");
        }

        @Override
        public void onError(AsyncEvent event) throws IOException {
            System.out.println("On error");
        }

        @Override
        public void onStartAsync(AsyncEvent event) throws IOException {
            System.out.println("On start async");
        }
    });

    ac.start(new Runnable() {
        @Override
        public void run() {
            for (int i = 0; i <= 10; i++) {
                System.out.println("Async task: "
                        + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                }
            }
            ac.complete();
        }
    });

    pw.write("end");
    pw.close();
}
}
@WebServlet(name=“VideoUploader”,urlPatterns={”/VideoUploader},
asyncSupported=true)
@多重配置
公共类视频上载程序扩展HttpServlet{
@凌驾
受保护的void doGet(HttpServletRequest请求、HttpServletResponse响应)
抛出ServletException、IOException{
doPost(请求、响应);
}
@凌驾
受保护的void doPost(HttpServletRequest请求、HttpServletResponse响应)
抛出ServletException、IOException{
final PrintWriter pw=response.getWriter();
final AsyncContext ac=request.startAsync();
ac.setTimeout(80000);
ac.addListener(新的AsyncListener(){
@凌驾
public void onComplete(AsyncEvent事件)引发IOException{
System.out.println(“完成时”);
}
@凌驾
public void onTimeout(AsyncEvent事件)引发IOException{
System.out.println(“超时时”);
}
@凌驾
public void onError(AsyncEvent事件)引发IOException{
System.out.println(“错误时”);
}
@凌驾
公共void onStartAsync(AsyncEvent事件)引发IOException{
System.out.println(“启动时异步”);
}
});
ac.start(新的可运行(){
@凌驾
公开募捐{

对于(int i=0;i显然,您的浏览器将等待另一个线程完成。

涉及以下步骤

  • 客户端向服务器发送请求
  • 服务器从线程池分配线程(Servlet容器)
  • Servlet容器在(Servlet线程)中创建Servlet实例/重用现有Servlet实例并调用Servlet方法
  • 通过调用startAsync()使用服务内方法将启动新线程并将请求、响应实例传递给新线程以处理请求
    注意**新线程没有阻塞http连接,它只是jvm中的一个线程,此时没有锁定任何IO
  • Servlet线程存在服务方法并返回到线程池
    注意**此处响应尚未发送到客户端/浏览器
  • 在步骤4中启动的进程完成后,该线程将请求Servlet容器分配给新的Servlet线程,以将响应发送回客户端。
  • 只有在第6步,响应才会返回到客户端。因此,从客户端的角度来看,正常请求和使用“
    asyncSupported=true
    ”之间没有区别。

    Servlet 3.0通过使用“
    asyncSupported=true
    ”支持每个请求的线程而不是每个连接的线程。
    每个连接的线程将导致线程不足

    @WebServlet(name = "VideoUploader", urlPatterns = { "/VideoUploader" }, asyncSupported = true)
    @MultipartConfig
    public class VideoUploader extends HttpServlet {
    
    @Override
    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
    
    @Override
    protected void doPost(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
    
        final AsyncContext ac = request.startAsync();
        ac.setTimeout(80000);
    
        ac.addListener(new AsyncListener() {
    
            public void onComplete(AsyncEvent event) throws IOException {
                System.out.println("On complete");
            }
    
            public void onTimeout(AsyncEvent event) throws IOException {
                System.out.println("On timeout");
            }
    
            public void onError(AsyncEvent event) throws IOException {
                System.out.println("On error");
    
            }
    
            public void onStartAsync(AsyncEvent event) throws IOException {
                System.out.println("On start async");
    
            }
    
        });
    
        ac.start(new Runnable() {
    
            public void run() {
                System.out.println("Async task: "
                        + Thread.currentThread().getName());
                try {
                    for (Part part : ((HttpServletRequest) ac.getRequest())
                            .getParts()) {
                        System.out.println("File received"); // You Should write
                                                                // file here
                                                                // like
                                                                // part.write("fileName");
                    }
                } catch (IOException e1) {
                    e1.printStackTrace();
                } catch (ServletException e1) {
                    e1.printStackTrace();
                }
                ac.complete();
                PrintWriter pw = null;
                try {
                    pw = ac.getResponse().getWriter();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                pw.write("end");
                pw.close();
            }
    
        });
    
    }
    }
    

    异步servlet将长时间运行的服务器端作业移交给不同的服务器线程。非阻塞IO是servlet 3.1中的一项新功能,用于处理传入数据阻塞或流传输速度慢于服务器读取速度的情况。这两种解决方案都是避免servlet线程不足的解决方案。它们不涉及将响应返回给客户端imm爱迪生

    由于您使用的是Ajax,而不是常规的浏览器文件上载,因此,如果您不关心servlet线程不足的问题,即使使用同步servlet,也应该可以在Ajax端轻松实现。Ajax本质上是异步的。下面是一个示例教程


    所以,您说在次线程结束之前不会发送响应,但在我的情况下,如果我没有选择要上载的文件,响应会立即发送,次线程稍后会完成,而与响应无关。这是不是让我感到困惑。也许我遗漏了一些东西。可能是因为我所在的位置吗放置complete()方法?或者我误解了什么?在您的实现中注意到了两个问题。1.您不应该在servlet线程中返回/写入响应(如果您使用asyn模式),请在ac.complete之前/之后将它们放在run块中。其次,您应该读取流(文件流)在run方法中上载。基本经验法则,您不能多次提交响应。另外,mike,您的表单不包括enctype=“multipart/form data”。我不想使用“multipart/form data”因为我认为在使用ajax时没有必要这样做。很高兴知道你所说的在servlet线程中编写响应的所有内容。我认为我的假设是,异步servlet用于获取响应,并让其他线程执行我们不需要任何反馈的工作,这是错误的。我没有找到任何关于这方面的清晰文档。对于这种行为我们会使用普通的thread.start()吗?
    @WebServlet(name = "VideoUploader", urlPatterns = { "/VideoUploader" }, asyncSupported = true)
    @MultipartConfig
    public class VideoUploader extends HttpServlet {
    
    @Override
    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
    
    @Override
    protected void doPost(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
    
        final AsyncContext ac = request.startAsync();
        ac.setTimeout(80000);
    
        ac.addListener(new AsyncListener() {
    
            public void onComplete(AsyncEvent event) throws IOException {
                System.out.println("On complete");
            }
    
            public void onTimeout(AsyncEvent event) throws IOException {
                System.out.println("On timeout");
            }
    
            public void onError(AsyncEvent event) throws IOException {
                System.out.println("On error");
    
            }
    
            public void onStartAsync(AsyncEvent event) throws IOException {
                System.out.println("On start async");
    
            }
    
        });
    
        ac.start(new Runnable() {
    
            public void run() {
                System.out.println("Async task: "
                        + Thread.currentThread().getName());
                try {
                    for (Part part : ((HttpServletRequest) ac.getRequest())
                            .getParts()) {
                        System.out.println("File received"); // You Should write
                                                                // file here
                                                                // like
                                                                // part.write("fileName");
                    }
                } catch (IOException e1) {
                    e1.printStackTrace();
                } catch (ServletException e1) {
                    e1.printStackTrace();
                }
                ac.complete();
                PrintWriter pw = null;
                try {
                    pw = ac.getResponse().getWriter();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                pw.write("end");
                pw.close();
            }
    
        });
    
    }
    }