tomcat7特性 serlvet async特性

标签: tomcat7 serlvet async | 发表时间:2017-10-12 11:13 | 作者:xiaoxiaoHer
出处:http://www.iteye.com

 

每个请求来到Web容器,Web容器会为其分配一个线程来专门负责该请求,直到完成处理前,该执行线程都不会被释放回容器。 执行线程会耗用系统资源,若有些请求需要长时间处理(例如长时间运算、等待某个资源),就会长时间占用执行线程。 
若这类的请求很多,许多执行线程都被长时间占用,而在web容器内,可以使用的线程都是有限的,这对于系统就会是个负担,甚至造成应用程式的性能瓶颈。

基本上一些需长时间处理的请求,通常客户端也较不在乎请求后要有立即的回应。若可以,让这类请求先释放容器分配给该请求的执行线程,让容器可以有机会将执行线程资源分配给其它的请求,可以减轻系统负担。

很多项目在遇到需长时间处理的任务时,经常启一个新线程或者扔到线程池中,这样不耽误任务主线的流程,这个servlet的asynch特性其实发挥同样的作用

释放了容器所分配执行线程的请求,其回应将被延后,直到处理完成(例如长时间运算完成、所需资源已获得)再行对客户端的回应, 如果超过浏览器的链接时长,会将servlet中的内容返回,而asyncContext中的内容则不能返回,服务器抛出java.lang.IllegalStateException错误

在Servlet 3.0中,提供了AsyncContext,对异步执行的上下文提供支持。在ServletRequest上提供了 startAsync( )方法,用于启动异步工作线程。而且AsynchContext还提供了Timeout等设置。

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

若要能调用ServletRequest的startAsync()使用AsyncContext,则此Servlet 必须能支援非同步处理,如果使用@WebServlet来标注,则可以设定其asyncSupported为true 。 例如:

   @WebServlet(urlPatterns = "/some.do", asyncSupported = true )   
public class AsyncServlet extends HttpServlet 
...   
  • 1
  • 2
  • 3

如果使用web.xml设定Servlet,则可以设定标签为true :

   ...   
<servlet>   
<servlet-name>AsyncServlet</servlet-name>   
<servlet-class>com.pkgname.AsyncServlet</servlet-class>   
<async-supported>true</async-supported>   
</servlet>   
...   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

如果Servlet将会异步处理,若其前端有过滤器,则过滤器亦需标示其支援异步处理,如果使用@WebFilter ,同样是可以设定其asyncSupported为true 。 例如:

   @WebFilter(urlPatterns = "/some.do", asyncSupported = true )   
public class AsyncFilter implements Filter{   
...   
  • 1
  • 2
  • 3

如果使用web.xml设定过滤器,则可以设定标签为true :

   ...   
<filter>   
< filter -name>AsyncFilter</ filter -name>   
< filter -class>com.pkgname.AsyncFilter</ filter -class>   
<async-supported>true</async-supported>   
</ filter >   
...   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

注意: 
使用异步处理方式,web容器的请求处理线程释放了,可以服务其他的请求处理。但是该Request的处理并没有结束,在使用AsyncContext的complete或者dispatch完成后,这个request的处理才结束。

   简单的示例:
  • 1
  • 2
   package com.ss;

import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

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;

//  import com.cndatacom.thread.BusinessHandleThread;

/**
 * 异步处理Servlet
 * @author 
 */

/**
 * asyncSupported属性默认是false,如果需要开启支持异步处理功能,需要设置为true
 */
@WebServlet(name = "AsyncServlet", urlPatterns = "/AsyncServlet2", asyncSupported = true)
public class AsyncServlet2 extends HttpServlet {
    /**
     * 
     */
    private static final long serialVersionUID = -2749650094193187229L;

    @Override
    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        response.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();

        Date date = new Date(System.currentTimeMillis());
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss Z");

        out.println("Servlet  begin --" + sdf.format(date) + "<br>");// 响应输出到客户端

        // 进入异步模式,调用业务处理线程进行业务处理
        // Servlet不会被阻塞,而是直接往下执行
        // 业务处理完成后的回应由AsyncContext管理
        AsyncContext asyncContext = request.startAsync();
        BusinessWorkerThread businessHandleThread = new BusinessWorkerThread(
                asyncContext);
        Thread thread = new Thread(businessHandleThread);
        thread.start();
        //asyncContext.start(businessHandleThread);//也可以用这种方法启动异步线程

        date = new Date(System.currentTimeMillis());
        out.println("Servlet end --" + sdf.format(date) + "<br>");
        out.flush();

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
   ------
  • 1
  • 2
   package com.ss;

import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.servlet.AsyncContext;
import javax.servlet.ServletResponse;

/**
 * 业务处理线程
 * 
 * @author 
 */
public class BusinessWorkerThread implements Runnable {

    // 异步操作的上下文对象,通过构造方法传进来
    private AsyncContext asyncContext;

    public BusinessWorkerThread(AsyncContext asyncContext) {
        this.asyncContext = asyncContext;
    }

    @Override
    public void run() {
        try {
            // do some work...
            Thread.sleep(8000); // 和browser的timeout时间相关。如果browser上timeout是30s,则大于30时,网络已经断开。这是就会异常。

            ServletResponse response = asyncContext.getResponse();
            PrintWriter out = response.getWriter();
            Date date = new Date(System.currentTimeMillis());
            SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss Z");

            out.println("business worker finished --"+ sdf.format(date));// 响应输出到客户端

            // 告诉启动异步处理的Servlet异步处理已完成,Servlet就会提交请求响应
            asyncContext.complete();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
   输出: 在浏览器中,输出的内容按照后面的时间显示在页面上。
  • 1
  • 2
   Servlet begin --22:33:57 +0800
Servlet end --22:33:57 +0800
business worker finished --22:34:05 +0800
  • 1
  • 2
  • 3

注意: 使用浏览器访问,因为各个浏览器的http请求超时设置不同,比如我的chrome是30秒。AsyncContext中对应的工作线程的持续时间需要小于浏览器的http超时时间。

AsyncListener

AsyncContext还可以设置一个Listener,对4个事件进行处理:

示例:

    package com.ss;

import java.io.IOException;

import javax.servlet.AsyncContext;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class AsyncServletTest
 */
@WebServlet(asyncSupported = true, urlPatterns = { "/AsyncTest" })
public class AsyncServletTest extends HttpServlet {

    String param = "";

    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public AsyncServletTest() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
     *      response)
     */

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {

        // 1 start async
        final AsyncContext ctx = req.startAsync();
        param = ctx.getRequest().getParameter("seq");
        System.out.println("getRequest request seq: " + param);

        // 2 set the timeout
        ctx.setTimeout(0);

        // 3 add listener
        ctx.addListener(new AsyncListener() {

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

            @Override
            public void onStartAsync(AsyncEvent arg0) throws IOException {
                System.out.println("onStartAsync...");
            }

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

            @Override
            public void onComplete(AsyncEvent arg0) throws IOException {
                System.out.println("onComplete...");
            }
        });

        // 4 run a thread
        ctx.start(new Runnable() {
            @Override
            public void run() {
                String seq = ctx.getRequest().getParameter("seq");

                System.out.println(">>>>>now respone: " + seq);

                int n = 0;
                try {
                    // hold until receive exit
                    while (!param.equals("exit")) {

                        n++;
                        if (n % 100000000 == 0) {

                            System.out.println(seq + ": ..." + n);
//                          
                        }
                    }
                    ctx.getResponse().getWriter().write(seq+" -- "+n);

                } catch (IOException e) {
                    e.printStackTrace();
                }

                ctx.complete();
            }

        });
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    protected void doPost(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        System.out.println("doPost...");
    }

}


已有 0 人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



相关 [tomcat7 serlvet async] 推荐:

tomcat7特性 serlvet async特性

- - 编程语言 - ITeye博客
每个请求来到Web容器,Web容器会为其分配一个线程来专门负责该请求,直到完成处理前,该执行线程都不会被释放回容器. 执行线程会耗用系统资源,若有些请求需要长时间处理(例如长时间运算、等待某个资源),就会长时间占用执行线程. 若这类的请求很多,许多执行线程都被长时间占用,而在web容器内,可以使用的线程都是有限的,这对于系统就会是个负担,甚至造成应用程式的性能瓶颈.

tomcat7之websocket

- - ITeye博客
从tomcat7.0.26之后开始支持websocket,建议大家使用tomcat7.0.30,期间版本的接口有一些改动. chrome默认支持websocket. 其他浏览器可能由于安全原因,默认是关闭的. // 与7.0.27不同的,Tomcat改变了createWebSocketInbound方法的定义,增加了一个HttpServletRequest参数.

script的defer和async

- - 携程UED
我们常用的script标签,有两个和性能、js文件下载执行相关的属性:defer和async. defer的含义【摘自 https://developer.mozilla.org/En/HTML/Element/Script】. This Boolean attribute is set to indicate to a browser that the script is meant to be executed after the document has been parsed..

async vs defer 属性

- - 进步博客