Filter學習總結,順便提及點servlet3.0異步filter和異步監聽


 
Filter介紹:
    Filter在項目中經常可以用到,通常配置在web.xml中。是服務器端的一個組件,對於用戶的請求和響應數據進行過濾操作,控制是否讓用戶訪問到對應的web資源。常用於編碼更改、權限控制等操作。
 
過濾器的執行順序:
1333424123_7382.jpg
配置方式:web.xml
  1. <!--filter過濾器-->
  2. <filter>
  3. <!--filter名稱-->
  4. <filter-name>myCharacterFilter</filter-name>
  5. <!--filter處理的類-->
  6. <filter-class>com.filter.MyCharacterFilter</filter-class>
  7. <!--初始化參數-->
  8.     <init-param>
  9. <param-name>defaultCharset</param-name>
  10. <param-value>UTF-8</param-value>
  11. </init-param>
  12. </filter>
  13. <!--過濾器映射-->
  14. <filter-mapping>
  15. <!--和過濾器名相同-->
  16. <filter-name>myCharacterFilter</filter-name>
  17. <!--攔截的路徑-->
  18. <url-pattern>*.do</url-pattern>
  19. </filter-mapping>
  20.  
  21. <!--映射多個不同路徑,需要些多個<filter-mapping>-->
  22. <filter-mapping>
  23. <filter-name>myCharacterFilter</filter-name>
  24. <url-pattern>*.action</url-pattern>
  25. </filter-mapping>
    <filter>和<filter-mapping>的<filter-name>必須相同,多個不同路徑需配置多個不同的<filter-mapping>。
    初始化參數可以寫到<filter>的子節點<init-param>中,配置為鍵值對的方式,即<param-name>、<param-value>。
    Filter的實現類需要實現 javax.servlet.Filter接口,默認重寫init()、destroy()、doFilter()函數,這3個函數分別對應初始化、銷毀、過濾這3個生命周期。
 
生命周期:
    實例化:web容器在部署web應用程序時對所有過濾器進行實例化。web容器回調它的無參構造方法。
    初始化:啟動服務器時加載過濾器的實例,並自動調用init()函數。
    過濾:調用過濾器的doFilter()執行過濾,這個是過濾器的核心方法。
    銷毀:停止服務時調用destroy()函數,銷毀過濾器實例。
 
初始化參數獲取:
    通過init()函數的參數FilterConfig對象,filter. getInitParameter("初始化參數key")能拿到初始化參數。
 
過濾器鏈:
    過濾器可以在web.xml中配置多個,滿足對某一URL進行過濾條件時,會按照web.xml中配置的順序進行執行,構成過濾器鏈。舉例如下:
    請求某一URL執行過濾器 MyCharacterFilter   MyRoleFilter   MyCharacterFilter    執行后會調用filterChain.doFilter()方法繼續調用 MyRoleFilter    過濾器。
     MyCharacterFilter  :
  MyRoleFilter  :
    
    控制台輸出日志順序:
            MyCharacterFilter   start==do
RoleFilter doFilter  ===  start
RoleFilter doFilter  ===  end
MyCharacterFilter   end==do
    
<filter-mapping>的特殊參數- dispatcher:
    此參數根據配置不同,支持不同類型的請求, 可配置多個
    REQUEST(默認值):從客戶端直接請求過來會走這個過濾器,直接請求或redirect.sendRedirect("url");。
    FORWEARD:通過dispatcher的forward方法會走這個過濾器。request.getdispatcher("url").forward(request,response);或使用jsp指令 jsp:forward。
    INCLUDE:通過dispatcher的include()方法會走這個過濾器。 request.getdispatcher("url").include(request,response);或使用jsp指令 jspinclude。
    ERROR:通過web.xml中<error-page>過來的請求會走這個過濾器。
    ASYNC Servlet3.0添加了對另一種值的支持:異步處理 )。原有的servlet需要處理完業務邏輯再相應,現在會開啟另外一個線程單獨處理業務邏輯,servlet線程委托其他線程處理業務邏輯,自己在不生成響應的情況下返回至容器,提高並發訪問速度,減少服務器資源的占用。(下面有Demo)
 
Servlet3.0增加了對注解的支持,可以通過注解配置,不用在web.xml中配置。需要配合支持Tomcat7.0以上容器(支持servlet3.0)。配置內容:
IMG_2134.PNG
 
 
這里做Demo的時候遇到了點問題,Dynamic Web Module版本是2.5,想改成3.0。發現沒法改。(截圖是改好的),可以點擊右面的Runtimes,里面選擇web容器,
注意此處只有web容器本身能支持servlet3.0才能選擇3.0的Dynamic Web Module,比如Tomcat必須選擇Tomcat7.0++,選擇Apply-OK。然后再進來就能選擇3.0了。
 
 
Servlet3.0特性之filter-dispatcher(ASYNC):
    1.業務邏輯處理之前調用 AsyncContext   ctx  =  req .startAsync();
  2.創建線程、傳入ctx並調用具體業務邏輯。
  3.調用完成執行ctx的complete()函數。
Demo:
    ①.配置filter的dispatcher值為ASYNC,servlet的 async-supported值為true.
  1. <filter>
  2. <filter-name>roleFilter</filter-name>
  3. <filter-class>com.filter.MyRoleFilter</filter-class>
  4. <init-param>
  5. <param-name>username</param-name>
  6. <param-value>www</param-value>
  7. </init-param>
  8. </filter>
  9. <filter-mapping>
  10. <filter-name>roleFilter</filter-name>
  11. <url-pattern>*.action</url-pattern>
  12. <dispatcher>ASYNC</dispatcher>
  13. </filter-mapping>
  14. <servlet>
  15. <description></description>
  16. <display-name>LoginServlet2</display-name>
  17. <servlet-name>LoginServlet2</servlet-name>
  18. <servlet-class>com.servlet.LoginServlet2</servlet-class>
  19. <async-supported>true</async-supported>
  20. </servlet>
  21. <servlet-mapping>
  22. <servlet-name>LoginServlet2</servlet-name>
  23. <url-pattern>/LoginServlet.action</url-pattern>
  24. </servlet-mapping>
    ②.servlet的處理邏輯中加入req.startAsync()函數,創建一個新的線程傳入ctx對象並來執行業務邏輯
  1. resp.setContentType("text/html;charset=UTF-8");
  2. PrintWriter pw = resp.getWriter();
  3. pw.println("進入servlet時間" + new SimpleDateFormat("yyyy-Mm-dd HH:mm:ss").format(new Date()));
  4. pw.flush();
  5. AsyncContext ctx = req.startAsync();
  6. new Thread(new Executor(ctx)).start();
  7. pw.println("離開servlet時間" + new SimpleDateFormat("yyyy-Mm-dd HH:mm:ss").format(new Date()));
  8. pw.flush();
    ③.線程的run()函數執行邏輯后調用ctx的complete()函數通知容器異步處理完成。
  1. //等待10s,模擬業務邏輯
  2. try {
  3. Thread.sleep(10000);
  4. PrintWriter pw = ctx.getResponse().getWriter();
  5. pw.println("業務邏輯處理完成時間"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
  6. pw.flush();
  7. this.ctx.complete();
  8. } catch (Exception e) {
  9. e.printStackTrace();
  10. }
   搞定,親測結果OK。輸出結果:
   直接輸出(servlet已響應): 進入servlet時間2015-1015-19 12:15:46 離開servlet時間2015-1015-19 12:15:46 
   大約10S后輸出結果(單獨開線程異步處理): 業務邏輯處理完成時間2015-10-19 12:15:56
 
順便提及servlet3.0的異步處理的監聽器 AsyncListener,這個接口監控如下4種事件:
  1. 異步線程開始時,調用 AsyncListener 的 onStartAsync(AsyncEvent event) 方法;
  2. 異步線程出錯時,調用 AsyncListener 的 onError(AsyncEvent event) 方法;
  3. 異步線程執1333424123_7382.jpg行超時,則調用 AsyncListener 的 onTimeout(AsyncEvent event) 方法;
  4. 異步執行完畢時,調用 AsyncListener 的 onComplete(AsyncEvent event) 方法。 
 
要注冊一個 AsyncListener,只需將准備好的 AsyncListener 對象傳遞給 AsyncContext 對象的 addListener() 方法即可,如下所示:
  1. ctx.addListener(new AsyncListener() {
  2. @Override
  3. public void onTimeout(AsyncEvent arg0) throws IOException {
  4. System.out.println("listener===超時");
  5. }
  6. @Override
  7. public void onStartAsync(AsyncEvent arg0) throws IOException {
  8. System.out.println("listener===開始");
  9. }
  10. @Override
  11. public void onError(AsyncEvent arg0) throws IOException {
  12. System.out.println("listener===異常");
  13. }
  14. @Override
  15. public void onComplete(AsyncEvent arg0) throws IOException {
  16. System.out.println("listener===完成");
  17. }
  18. });
      經過測試,發現 onStartAsync() 這個函數沒有被調用,沒有找到原因!onComplete()正常被調用,onTimeout()debug的時候會打印出超時的信息。
 
 
IMG_2151.PNG
 
 
 
 
 
 
 
 
 
 
 
 
 
 
         
 





 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM