tomcat + spring mvc原理(五):tomcat Filter組件實現原理

tomcat + spring mvc原理(五):tomcat Filter組件實現原理

前言:

    原理(四)中假裝結束了tomcat消息處理的流程分析,其實偷偷留了私貨–Filter的這個部分依然屬於tomcat網絡消息處理的一個步驟。

Wrapper中Pipeline的收尾

    原理(四)最後用Wrapper中的StandardWrapperValve收尾,結論是

StandardWrapperValve是tomcat處理消息的邊界,在這個Value的invoke()方法中,消息被傳遞給了Servlet,從此進入了spring mvc的領域。

StandardWrapperValve的invoke方法的實現代碼很長,不過大部分內容都是異常的catch和處理,核心主要是獲取Servlet實例、構建FilterChain、判斷是否是異步Servlet和執行filterChain.doFilter方法。

   ······
   servlet = wrapper.allocate();
   
   ······
   ApplicationFilterChain filterChain =
        ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
        
   ······
   if (request.isAsyncDispatching()) {
    request.getAsyncContextInternal().doInternalDispatch();
   } else {
    filterChain.doFilter
        (request.getRequest(), response.getResponse());
   }
   ······

filterChain看上去很像原理(四)介紹的責任鏈,請求先依次經過註冊Filter的處理,在最後會調用Servlet的service方法.到達Servlet就意味着請求被傳遞到了spring mvc中。Servlet的默認實現是DispatcherServlet,這部分內容會在spring mvc模塊詳細介紹。

Filter的基本實現

public interface Filter {
  
    public default void init(FilterConfig filterConfig) throws ServletException {}

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

    public default void destroy() {}
      
}

    在業務邏輯中添加Filter,就需要實現這個接口。FilterChain調用doFilter()方法時,依次調用註冊的Filter的doFilter()方法,Filter是FilterChain中的基本單元。實際上,FilterChain中維護的是一個ApplicationFilterConfig的數組,這是因爲在調用doFilter時,並不能保證Filter的實現類已經被加載到內存中,但是每一個註冊過的Filter的類名(spring mvc在配置文件中配置,spring boot加載方式複雜一點)都會被保存在Context中。ApplicationFilterConfig中既有String變量保存類名,也有Filter的引用獲取已經構造好的實例對象。

public final class ApplicationFilterConfig implements FilterConfig, Serializable {
    ·····
    private final transient Context context;

    private transient Filter filter = null;

    private final FilterDef filterDef;
    ·····
}

其中的FilterDef中就存儲了filterClass的名字,這樣在需要獲取類實例時,就能直接newInstance()一個實例。

FilterChain的實現

    FilterChain中存儲了ApplicationFilterConfig的數組,整數n用來存儲數組的大小,整數pos用來存儲當前調用的Filter的index。FilterChain的doFilter()實際調用internalDoFilter()來實現Filter鏈的遍歷。首先是獲取當前位置的Filter的實例,如果Filter的實現類的實例已經加載,filterConfig.getFilter()能夠直接獲取,如果沒有加載,則根據類名構造一個實例。然後調用filter.doFilter(),其中傳入了請求消息體、應答消息體和FilterChain自身。由於這個Filter的遍歷並不是由循環而是由遞歸實現的,所以filter的doFilter()方法最後需要再次調用FilterChain的doFilter方法,這樣FilterChain可以pos++,執行下一個filter的doFilter()。

public final class ApplicationFilterChain implements FilterChain {
    ......
    private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];
    private int pos = 0;
    private int n = 0;
    private Servlet servlet = null;
    ......
    private void internalDoFilter(ServletRequest request,
                              ServletResponse response)
    throws IOException, ServletException {

    if (pos < n) {
        ApplicationFilterConfig filterConfig = filters[pos++];
        try {
            Filter filter = filterConfig.getFilter();
    ......
            } else {
                filter.doFilter(request, response, this);
            }
    ......
        } else {
            servlet.service(request, response);
        }
    ......
  }

在所有註冊的Filter都遍歷一遍之後,FilterChain會調用Servlet的service方法處理請求,自此,請求正式進入到spring mvc的領域。

最後解釋一下ApplicationFilterFactory。ApplicationFilterFactory中的createFilterChain()方法中構造了一個ApplicationFilterChain對象,然後能夠從Context中獲得FilterMap,由這個FilterMap的內容填充了FilterChain的對象,這是就是FilterChain實現初始化的關鍵點。
相關文章:
tomcat + spring mvc原理(一):tomcat原理綜述和靜態架構
tomcat + spring mvc原理(二):tomcat容器初始化加載和啓動
tomcat + spring mvc原理(三):tomcat網絡請求的監控與處理1
tomcat + spring mvc原理(四):tomcat網絡請求的監控與處理2

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章