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