<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    聶永的博客

    記錄工作/學(xué)習(xí)的點(diǎn)點(diǎn)滴滴。

    Servlet 3.0筆記之異步攔截器(async filter)的學(xué)習(xí)

    異步Servlet有時(shí)需要一個(gè)攔截器,但必須是異步的Filter,否則將會(huì)報(bào)錯(cuò):
    嚴(yán)重: Servlet.service() for servlet [com.learn.servlet3.async.DemoAsyncLinkServlet] in context with path [/servlet3] threw exceptionjava.lang.IllegalStateException: Not supported.
    因此異步的Filter攔截異步Servlet,不要搞錯(cuò)。
    我們需要預(yù)先定義這么一個(gè)異步連接,每秒輸出一個(gè)數(shù)字字符串,從0到99,諸如下面HTML字符串:
    <div>2</div>
    最后輸出Done!
    給出兩個(gè)訪問地址,一個(gè)用于被攔截(/demoAsyncLink),一個(gè)用于單獨(dú)訪問(/demoAsyncLink2),便于對照:
    /**
    * 模擬長連接實(shí)現(xiàn),每秒輸出一些信息
    *
    * @author yongboy
    * @date 2011-1-14
    * @version 1.0
    */
    @WebServlet(
    urlPatterns = { "/demoAsyncLink", "/demoAsyncLink2" },
    asyncSupported = true
    )
    public class DemoAsyncLinkServlet extends HttpServlet {
    private static final long serialVersionUID = 4617227991063927036L;

    protected void doGet(HttpServletRequest request,
    HttpServletResponse response) throws ServletException, IOException {
    response.setHeader("Cache-Control", "private");
    response.setHeader("Pragma", "no-cache");
    response.setHeader("Connection", "Keep-Alive");
    response.setHeader("Proxy-Connection", "Keep-Alive");
    response.setContentType("text/html;charset=UTF-8");

    PrintWriter out = response.getWriter();
    out.println("<div>Start ...</div>");
    out.flush();

    AsyncContext asyncContext = request.startAsync(request, response);

    new CounterThread(asyncContext).start();
    }

    private static class CounterThread extends Thread {
    private AsyncContext asyncContext;
    public CounterThread(AsyncContext asyncContext) {
    this.asyncContext = asyncContext;
    }

    @Override
    public void run() {
    int num = 0;
    int max = 100;
    int interval = 1000;

    // 必須設(shè)置過期時(shí)間,否則將會(huì)出連接過期,線程無法運(yùn)行完畢異常
    asyncContext.setTimeout((max + 1) * interval);
    PrintWriter out = null;

    try {
    try {
    out = asyncContext.getResponse().getWriter();
    } catch (IOException e) {
    e.printStackTrace();
    }

    while (true) {
    out.println("<div>" + (num++) + "</div>");
    out.flush();

    if (num >= max) {
    break;
    }

    Thread.sleep(interval);
    }
    } catch (InterruptedException e) {
    e.printStackTrace();
    }

    if (out != null) {
    out.println("<div>Done !</div>");
    out.flush();
    out.close();
    }

    asyncContext.complete();
    }
    }
    }
    若想讓HttpServletResponse包裝器發(fā)揮包裝的效果,須調(diào)用帶有參數(shù)的startAsync(request, response)方法開啟異步輸出,否則MarkWapperedResponse將不起作用。因?yàn)椋舨粋鬟f現(xiàn)有的request,response對象,將會(huì)調(diào)用原生的request和response對象。
    在tomcat7下面,異步連接超時(shí)時(shí)間為10000單位,若不指定超時(shí)時(shí)間,遞增的數(shù)字不會(huì)按照預(yù)想完整輸出到99。
    我們假設(shè)需要定義這樣一個(gè)Filter,為每一次的異步輸出的內(nèi)容增加一個(gè)特殊標(biāo)記:
    <!--marked filter-->
    <div>2</div>
    邏輯很簡單,作為示范也不需要多復(fù)雜。
    再看看一個(gè)異步Filter的代碼:
    /**
    * 異步攔截器
    *
    * @author yongboy
    * @date 2011-1-14
    * @version 1.0
    */
    @WebFilter(
    dispatcherTypes = {
    DispatcherType.REQUEST,
    DispatcherType.FORWARD,
    DispatcherType.INCLUDE
    },
    urlPatterns = { "/demoAsyncLink" },
    asyncSupported = true //支持異步Servlet
    )
    public class AsyncServletFilter implements Filter {
    private Log log = LogFactory.getLog(AsyncServletFilter.class);

    public AsyncServletFilter() {
    }

    public void destroy() {
    }

    public void doFilter(ServletRequest request, ServletResponse response,
    FilterChain chain) throws IOException, ServletException {

    log.info("it was filted now");

    MarkWapperedResponse wapper = new MarkWapperedResponse(
    (HttpServletResponse) response);

    chain.doFilter(request, wapper);
    }

    public void init(FilterConfig fConfig) throws ServletException {
    }
    }
    很簡單,添加上asyncSupported = true屬性即可。在上面Filter中包裝了一個(gè)HttpServletResponse對象,目的在于返回一個(gè)定制的PrintWriter對象,簡單重寫flush方法(不見得方法多好):
    /**
    * HttpServletResponse簡單包裝器,邏輯簡單
    *
    * @author yongboy
    * @date 2011-1-14
    * @version 1.0
    */
    public class MarkWapperedResponse extends HttpServletResponseWrapper {
    private PrintWriter writer = null;
    private static final String MARKED_STRING = "<!--marked filter--->";

    public MarkWapperedResponse(HttpServletResponse resp) throws IOException {
    super(resp);

    writer = new MarkPrintWriter(super.getOutputStream());
    }

    @Override
    public PrintWriter getWriter() throws UnsupportedEncodingException {
    return writer;
    }

    private static class MarkPrintWriter extends PrintWriter{

    public MarkPrintWriter(OutputStream out) {
    super(out);
    }

    @Override
    public void flush() {
    super.flush();

    super.println(MARKED_STRING);
    }
    }
    }
    在瀏覽器端請求被包裝的/demoAsyncLink鏈接,截圖以及firebug檢測截圖如下:
     
    可以在瀏覽器內(nèi)同時(shí)請求/demoAsyncLink2前后作為對比一下。

    posted on 2011-01-15 19:39 nieyong 閱讀(8157) 評論(0)  編輯  收藏 所屬分類: Servlet3

    公告

    所有文章皆為原創(chuàng),若轉(zhuǎn)載請標(biāo)明出處,謝謝~

    新浪微博,歡迎關(guān)注:

    導(dǎo)航

    <2011年1月>
    2627282930311
    2345678
    9101112131415
    16171819202122
    23242526272829
    303112345

    統(tǒng)計(jì)

    常用鏈接

    留言簿(58)

    隨筆分類(130)

    隨筆檔案(151)

    個(gè)人收藏

    最新隨筆

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 亚洲国产成人手机在线电影bd | 亚洲AV日韩AV永久无码色欲| 亚洲人成网站在线观看播放动漫| 老司机亚洲精品影院| 午夜亚洲AV日韩AV无码大全| 日韩亚洲人成在线综合日本| 亚洲国产精品一区第二页| 久久精品国产亚洲av麻豆 | 性色av免费观看| 成人男女网18免费视频| 日韩激情淫片免费看| 四虎永久免费影院在线| 一本久久综合亚洲鲁鲁五月天 | 鲁大师在线影院免费观看 | 女人隐私秘视频黄www免费| a在线视频免费观看| 久久精品中文字幕免费| 亚洲w码欧洲s码免费| 免费观看的毛片大全| 成人免费毛片视频| 免费在线观看你懂的| 亚洲最大av无码网址| 亚洲av最新在线网址| 亚洲制服丝袜一区二区三区| 亚洲日韩中文字幕无码一区| 国产亚洲精品第一综合| 丁香花在线观看免费观看图片| 在线看片免费人成视频福利| 精品国产sm捆绑最大网免费站 | 三年片在线观看免费| 97免费人妻无码视频| 国产最新凸凹视频免费| 亚洲人成中文字幕在线观看| 337p日本欧洲亚洲大胆艺术| 亚洲欧美日韩综合久久久| 永久免费精品影视网站| 无码专区AAAAAA免费视频| 久久精品无码一区二区三区免费| 免费二级毛片免费完整视频| 亚洲成A人片在线观看无码不卡| 亚洲制服丝袜第一页|