AsyncContext简介

为了支持异步处理,在Servlet 3.0中,在ServletRequest上提供了startAsync()方法:
AsyncContext startAsync() throws java.lang.IllegalStateException;
AsyncContext startAsync(ServletRequest servletRequest,
                        ServletResponse servletResponse)
                        throws java.lang.IllegalStateException

这两个方法都会返回AsyncContext接口的实现对象,前者会直接利用原有的请求与响应对象来创建AsyncContext,后者可以传入自行创建的请求、响应封装对象。在调用了startAsync()方法取得AsyncContext对象之后,此次请求的响应会被延后,并释放容器分配的线程。

可以通过AsyncContext的getRequest()、getResponse()方法取得请求、响应对象,此次对客户端的响应将暂缓至调用AsyncContext的complete()或dispatch()方法为止,前者表示响应完成,后者表示将调派指定的URL进行响应。

若要能调用ServletRequest的startAsync()以取得AsyncContext,必须告知容器此Servlet支持异步处理,如果使用@WebServlet来标注,则可以设置其asyncSupported为true。例如:
@WebServlet(urlPatterns = "/some.do", asyncSupported = true)
public class AsyncServlet extends HttpServlet {
...
如果使用web.xml设置Servlet,则可以在<servlet>中设置<async-supported>标签为true:
...
<servlet>
    <servlet-name>AsyncServlet</servlet-name>
    <servlet-class>cc.openhome.AsyncServlet</servlet-class>
    <async-supported>true</async-supported>
</servlet>
...

如果Servlet将会进行异步处理,若其前端有过滤器,则过滤器亦需标示其支持异步处理,如果使用@WebFilter,同样可以设置其asyncSupported为true。例如:
@WebFilter(urlPatterns = "/some.do", asyncSupported = true)
public class AsyncFilter implements Filter{
...

如果使用web.xml设置过滤器,则可以设置<async-supported>标签为true:
...
<filter>
    <filter-name>AsyncFilter</filter-name>
    <filter-class>cc.openhome.AsyncFilter</filter-class>
    <async-supported>true</async-supported>
</filter>
...

下面示范一个异步处理的简单例子:
AsyncContextDemo  AsyncServlet.java
package cc.openhome;
import java.io.*;
import java.util.concurrent.*;
import javax.servlet.*;
import javax.servlet.annotation.*;
import javax.servlet.http.*;
@WebServlet(name="AsyncServlet", urlPatterns={"/async.do"},
             asyncSupported = true)
public class AsyncServlet extends HttpServlet {
    private ExecutorService executorService =
                      Executors.newFixedThreadPool(10);
    @Override
    protected void doGet(HttpServletRequest request,
                                 HttpServletResponse response)
    throws ServletException, IOException {
        response.setContentType("text/html; charset=UTF8");
        AsyncContext ctx = request.startAsync();
        executorService.submit(new AsyncRequest(ctx));
    }
    @Override
    public void destroy() {
         executorService.shutdown();
    }   
}

首先告诉容器,这个Servlet支持异步处理?,对于每个请求,Servlet会取得其AsyncContext?,并释放容器所分配的线程,响应被延后。对于这些被延后响应的请求,创建一个实现Runnable接口的AsyncRequest对象,并将其调度一个线程池(Thread pool)?,线程池的线程数量是固定的,让这些必须长时间处理的请求,在这些有限数量的线程中完成,而不用每次请求都占用容器分配的线程。

AsyncRequest是个实现Runnable的类,其模拟了长时间处理:
AsyncContextDemo  AsyncRequest.java
package cc.openhome;
import java.io.PrintWriter;
import javax.servlet.AsyncContext;
public class AsyncRequest implements Runnable {
    private AsyncContext ctx;
    public AsyncRequest(AsyncContext ctx) {
        this.ctx = ctx;
    }
    @Override
    public void run() {
        try {
            Thread.sleep(10000); 
            PrintWriter out = ctx.getResponse().getWriter();
            out.println("久等了...XD");
            ctx.complete();    
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

请求与响应对象都封装在AsyncContext中,所以AsyncRequest建构时必须接受AsyncContext实例。范例中以暂停线程的方式来模拟长时间处理?,并输出简单的字符串作为响应文字?,最后调用AsyncContext的complete()对客户端完成响应?。

AsyncContext异步输出报错:java.lang.NullPointerException

05-02

[code=java]rn@WebServlet(urlPatterns="/asyncPrint",asyncSupported = true)rnpublic class LoginServlet extends HttpServlet rnrn private static final long serialVersionUID = -1428172087125899118L;rn protected void doPost(HttpServletRequest req, HttpServletResponse resp)rn throws ServletException, IOException rn rn resp.setContentType("text/html;charset=UTF-8");rn AsyncContext async = req.startAsync();rn new CounterThread(async).start();rn rnrnclass CounterThread extends Threadrn rn private AsyncContext asyncContext;rn public CounterThread(AsyncContext asyncContext)rn this.asyncContext = asyncContext;rn rn public void run() rn if(asyncContext == null)rn System.out.println(asyncContext);rn return;rn rn tryrn rn PrintWriter writer= asyncContext.getResponse().getWriter();rn for( int i=0;i<50;i++)rn rn int rand = new Random().nextInt(10)*1000;rn printPage(writer,"this print is " + rand);rn Thread.sleep(rand);rn rn writer.close();rn catch(Exception e)rn e.printStackTrace();rn rn rn private void printPage(PrintWriter writer,String str)rn rn writer.write(" " + str + ""); rn writer.flush();rn rnrn[/code]rnrn每次调用,都报错:rnjava.lang.NullPointerExceptionrn at org.apache.coyote.http11.InternalOutputBuffer.realWriteBytes(InternalOutputBuffer.java:215)rn at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:480)rn at org.apache.coyote.http11.InternalOutputBuffer.flush(InternalOutputBuffer.java:119)rn at org.apache.coyote.http11.AbstractHttp11Processor.action(AbstractHttp11Processor.java:799)rn at org.apache.coyote.Response.action(Response.java:174)rn at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:366)rn at org.apache.catalina.connector.OutputBuffer.flush(OutputBuffer.java:333)rn at org.apache.catalina.connector.CoyoteWriter.flush(CoyoteWriter.java:98)rn at cn.cloud.action.CounterThread.printPage(LoginServlet.java:69)rn at cn.cloud.action.CounterThread.run(LoginServlet.java:53)rn五月 02, 2014 10:03:16 上午 org.apache.catalina.core.StandardContext reloadrn信息: Reloading Context with name [/jshop] has startedrn五月 02, 2014 10:03:16 上午 org.apache.catalina.core.StandardContext reloadrn信息: Reloading Context with name [/jshop] is completed

没有更多推荐了,返回首页

私密
私密原因:
请选择设置私密原因
  • 广告
  • 抄袭
  • 版权
  • 政治
  • 色情
  • 无意义
  • 其他
其他原因:
120
出错啦
系统繁忙,请稍后再试