Tomcat深入淺出——Filter與Listener(五)

2022-07-10 21:00:33

一、Filter過濾器

1.1 Filter過濾器的使用

  • 這是過濾器介面的方法
public interface Filter {
    default void init(FilterConfig filterConfig) throws ServletException {
    }

    void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;

    default void destroy() {
    }
}
  • 一般情況下我們都在過濾器中新增公共的程式碼
  • 例如我們經常設定字元編碼utf-8,為了減少重複的操作,我們直接在過濾器中設定即可。
@WebFilter("/*")
public class MyFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //在Filter物件第一次被建立的時候呼叫,並且只呼叫一次
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //doFilter()只要使用者傳送一次請求,則執行一次,傳送N次,則執行N次。在這個方法中編寫過濾規則
        System.out.println("doFilter方法,前1");
        //解決跨域問題
        HttpServletResponse resp = (HttpServletResponse) servletResponse;
        resp.setHeader("Access-Control-Allow-Origin", "*");
        resp.setHeader("Access-Control-Allow-Headers", "*");
        resp.setHeader("Access-Control-Allow-Method", "*");

        //執行下一個過濾器,如果說下一個不是過濾器,則會執行servlet
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("doFilter方法,後1");
    }


    @Override
    public void destroy() {
        //在Filter物件被釋放/銷燬之前呼叫,並且只呼叫一次
        System.out.println("destroy方法");
    }
}
  • init方法:在Filter物件第一次被建立的時候呼叫,並且只呼叫一次

  • doFilter方法:只要使用者傳送一次請求,則執行一次,傳送N次,則執行N次。在這個方法中編寫過濾規則

  • destroy方法:在Filter物件被釋放/銷燬之前呼叫,並且只呼叫一次

  • filterChain.doFilter(request, response);執行下一個過濾器,如果下一個不是過濾器,則執行Servlet

目標Servlet是否執行取決於兩個條件:

  • 過濾器中是否編寫了filterChain.doFilter(request, response);
  • 使用者發的請求路徑是否和Servlet的請求路徑一致

注意:

  • Filter的優先順序天生就比Servlet高
  • 使用@WebFilter的時候,Filter執行順序根據類名順序執行。
  • Filter的生命週期與Servlet一樣,但是Filter會在伺服器啟動的時候就預設建立物件,而Servlet卻需要設定才可以。
  • 如果在web.xml中設定兩個或者多個過濾器時,執行順序根據<filter-mapping>的先後。

1.2 Filter的責任鏈設計模式

  • 我們先來看一下兩個過濾器的執行過程是什麼樣的

  • Filter過濾器的doFilter方法,執行順序遵循的是棧結構,但是過濾器本身的生命週期就和佇列差不多吧。
  • 其實doFilter方法,就是一種責任鏈設計模式!
//模仿棧
//模仿Filter設計模式
//缺點:在編譯階段已經完全確定了呼叫關係
//如果想要改變呼叫順序,必須要修改java程式碼
//違背了OCP原則(開閉原則)
public class Test {
    public static void main(String[] args) {
        System.out.println("main方法執行");
        m1();
        System.out.println("main執行完畢");
    }
    public static void m1() {
        System.out.println("m1方法執行");
        m2();
        System.out.println("m1執行完畢");
    }
    public static void m2() {
        System.out.println("m2方法執行");
        m3();
        System.out.println("m2執行完畢");
    }
    public static void m3() {
        System.out.println("目標正在執行中");
    }
}

  • 這是執行的結果,是不是和Filter一樣~~~