美文网首页
Tomcat中Filter原理

Tomcat中Filter原理

作者: 柚子过来 | 来源:发表于2018-04-11 14:07 被阅读0次

之前在学习Java中功能增强的方法时经常说到过滤器,虽会用但是不知道为什么我们写一个类实现Filter接口就可以实现请求拦截了?现在以最常见的web容器Tomcat为例看看到底是为什么(Tomcat功能块很多,这里只看Filter这一部分)。

Tomcat的Filter是责任链模式的典型例子,我们可以定义多个Filter,在每个过滤器的doFilter方法中实现过滤逻辑并执行filterChain.doFilter(request,response).所以我们定义的Filter是由FilterChain来调用的,那是什么时候创建的FilterChain实例,它又是什么时候调用的filter呢?

先看FilterChain的定义:

final class ApplicationFilterChain implements FilterChain {
private static final ThreadLocal<ServletRequest> lastServicedRequest;   **************
private static final ThreadLocal<ServletResponse> lastServicedResponse;  **************
public static final int INCREMENT = 10;
private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0]; ************
private int pos = 0;
private int n = 0;
private Servlet servlet = null;   **************
... ...
}

它里面以ThreadLocal存储request和response,所以这个FilterChain应该是线程共享的,那它应该是在容器初始化的时候就创建出实例了

看tomcat的代码目录发现下面几个和Filter相关的实现类


image.png

FilterFactory中有初始化FilterChain的静态工厂方法createFilterChain。

说了这些,最重要的信息就是是FilterChain执行了我们的Filter,我们看它的doFilter方法:

private void internalDoFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {

    //如果filter还没执行完就执行剩下的filter
    if (this.pos < this.n) {

        //FilterChain中有个数组域存放了所有的Filter信息,按顺序遍历执行所有filter
        ApplicationFilterConfig filterConfig = this.filters[this.pos++];

        try {
            //根据filter信息获取Filter实例
            Filter filter = filterConfig.getFilter();
            if (request.isAsyncSupported() && "false".equalsIgnoreCase(filterConfig.getFilterDef().getAsyncSupported())) {
                request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", Boolean.FALSE);
            }

            if (Globals.IS_SECURITY_ENABLED) {
                Principal principal = ((HttpServletRequest)request).getUserPrincipal();
                Object[] args = new Object[]{request, response, this};
                SecurityUtil.doAsPrivilege("doFilter", filter, classType, args, principal);
            } else {

                //执行filter的doFilter方法(在我们Filter的doFilter中调用filterChain.doFilter就会循环回来调用下一个Filter了)
                filter.doFilter(request, response, this);
            }

        } catch(){... ...}

    } else {  //如果Filter全部执行完了就调用servlet的service方法 ************
        try {
            if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
                lastServicedRequest.set(request);
                lastServicedResponse.set(response);
            }

            if (request.isAsyncSupported() && !this.servletSupportsAsync) {
                request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", Boolean.FALSE);
            }

            if (request instanceof HttpServletRequest && response instanceof HttpServletResponse && Globals.IS_SECURITY_ENABLED) {
                Principal principal = ((HttpServletRequest)request).getUserPrincipal();
                Object[] args = new Object[]{request, response};
                SecurityUtil.doAsPrivilege("service", this.servlet, classTypeUsedInService, args, principal);
            } else {
                this.servlet.service(request, response);
            }
        } catch(){... ...}
        finally {
            if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
                lastServicedRequest.set((Object)null);
                lastServicedResponse.set((Object)null);
            }

        }

    }
}

从上面可以看出两个信息:1、FilerChain是怎么执行了所有的Filter的。2、Servlet是在Filter执行完后执行的。

所以容器在接收请求后会调用filterChain的doFilter方法,所有Filter执行完后会调用Servlet?

thinking:一个request过来是谁接受的?我们的服务器到tomcat容器再到应用服务?

相关文章

网友评论

      本文标题:Tomcat中Filter原理

      本文链接:https://www.haomeiwen.com/subject/mpeohftx.html