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