美文网首页
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