Servlet Filter工作原理

前言

本文主要探讨Filter的链式处理结构,不会过多赘述Filter的基本功能。

Filter的链式结构

一直一来,我对多个filter如何能够实现链式处理的结构很好奇。大体说来,假若Filter A处理完后,可以将request和response交由后续的Filter B处理,这很像责任链模式(Chain of Responsibility Pattern)。但实际上它不是,而是采用类似注册查找的方式。

一个filter的核心方法为dofilter,其核心结构为:

public void doFilter(ServletRequest req, ServletResponse res,
        FilterChain chain) {
    //此处编写该filter的核心处理代码
    //...
    chain.doFilter(request, response);
}

我们怎么知道当前filter执行后,谁是接下来执行的filter呢?可以看到,filter在执行完自己的处理方法后,将request和response交给了FilterChain 的doFilter方法。FilterChain在tomcat中的具体实现类为ApplicationFilterChain,反编译后其核心代码如下:

public void doFilter(ServletRequest request, ServletResponse response) {
    // some code before
    internalDoFilter(request, response);
    // some code after
}

private void internalDoFilter(ServletRequest request,
        ServletResponse response) {
    ApplicationFilterConfig filterConfig = this.filters[(this.pos++)];
    Filter filter = null;
    filter = filterConfig.getFilter();
    filter.doFilter(request, response, this);
}

可以看到,ApplicationFilterChain的doFilter方法调用了internalDoFilter方法,internalDoFilter的功能为,从当前webcontext中注册的所有filters中得到下一个filter(通过pos变量累加来得到下一个Filter的数组位置)。然后调用该filter的doFilter方法,依次类推,周而复始及至后续的所有filter。

值得注意的是,为了保证叙述的简洁,上述源代码去除了很多,只保留了能说明问题的几句。