Tomcat源码分析【十六】请求处理过程分析之创建与执行过滤器链

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】
免费领取10G资料包与项目实战视频资料

文章首发于:clawhub.club


filter是Servlet的规范,是在请求进入容器后,执行Servlet.service方法之前执行。
Tomcat处理filter分为三步:

  • 上下文初始化时读取web.xml中的filter数据
  • 请求处理时,根据请求路径找到相应的过滤器
  • 执行过滤器链,调用doFilter方法与目标方法。

初始化filter数据

首先在ContextConfig初始化时,读取web.xml配置文件,将其中的filter信息封装为FilterDef存储到StandardContext:

    private void configureContext(WebXml webxml) {
    //略......
    for (FilterDef filter : webxml.getFilters().values()) {
        if (filter.getAsyncSupported() == null) {
             filter.setAsyncSupported("false");
        }
        context.addFilterDef(filter);
    }
    for (FilterMap filterMap : webxml.getFilterMappings()) {
        context.addFilterMap(filterMap);
    }
    //略......
    }

之后在StandardContext初始化时调用filterStart,组装好filterConfigs供后期使用:

     /**
         * Configure and initialize the set of filters for this Context.
         * @return <code>true</code> if all filter initialization completed
         * successfully, or <code>false</code> otherwise.
         */
        public boolean filterStart() {

            if (getLogger().isDebugEnabled()) {
                getLogger().debug("Starting filters");
            }
            // Instantiate and record a FilterConfig for each defined filter
            boolean ok = true;
            synchronized (filterConfigs) {
                filterConfigs.clear();
                for (Entry<String,FilterDef> entry : filterDefs.entrySet()) {
                    String name = entry.getKey();
                    if (getLogger().isDebugEnabled()) {
                        getLogger().debug(" Starting filter '" + name + "'");
                    }
                    try {
                        //这里会调用 Filter.init 方法
                        ApplicationFilterConfig filterConfig =
                                new ApplicationFilterConfig(this, entry.getValue());
                        filterConfigs.put(name, filterConfig);
                    } catch (Throwable t) {
                        t = ExceptionUtils.unwrapInvocationTargetException(t);
                        ExceptionUtils.handleThrowable(t);
                        getLogger().error(sm.getString(
                                "standardContext.filterStart", name), t);
                        ok = false;
                    }
                }
            }

            return ok;
        }

创建过滤器链

创建过滤器链方法调用位于StandardWrapperValve的invoke中:

     //为这个请求创建过滤器链
    ApplicationFilterChain filterChain =
            ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);

进入ApplicationFilterFactory中:

    /**
         * 构造一个FilterChain实现,它将封装指定servlet实例的执行。
         *
         * @param request 我们正在处理的servlet请求,javax.servlet.ServletRequest
         * @param wrapper 管理servlet实例的包装器  org.apache.catalina.Wrapper
         * @param servlet 要包装的servlet实例 javax.servlet.Servlet
         * @return 配置的FilterChain实例,如果不执行,则为null。
         */
        public static ApplicationFilterChain createFilterChain(ServletRequest request,
                                                               Wrapper wrapper, Servlet servlet) {

            // 如果没有要执行的servlet,则返回null
            if (servlet == null)
                return null;

            // 创建并初始化过滤器链对象
            ApplicationFilterChain filterChain = null;
            //这里的Request为org.apache.catalina.connector.Request
            if (request instanceof Request) {
                Request req = (Request) request;
                //SecurityManager是否打开
                if (Globals.IS_SECURITY_ENABLED) {
                    // Security: Do not recycle 不回收
                    filterChain = new ApplicationFilterChain();
                } else {
                    //从请求中获取ApplicationFilterChain,也就是回收的
                    filterChain = (ApplicationFilterChain) req.getFilterChain();
                    if (filterChain == null) {
                        filterChain = new ApplicationFilterChain();
                        req.setFilterChain(filterChain);
                    }
                }
            } else {
                // 正在使用的请求调度程序,ApplicationDispatcher调用过来的
                filterChain = new ApplicationFilterChain();
            }

            //设置将在这个链的末尾执行的servlet。
            filterChain.setServlet(servlet);
            //关联的servlet实例是否支持异步处理?
            filterChain.setServletSupportsAsync(wrapper.isAsyncSupported());

            // 获取此上下文的过滤器映射
            StandardContext context = (StandardContext) wrapper.getParent();
            FilterMap filterMaps[] = context.findFilterMaps();

            // 如果没有过滤器映射,我们就完成了
            if ((filterMaps == null) || (filterMaps.length == 0))
                return filterChain;

            // 获取匹配筛选器映射所需的信息
            DispatcherType dispatcher =
                    (DispatcherType) request.getAttribute(Globals.DISPATCHER_TYPE_ATTR);

            String requestPath = null;
            Object attribute = request.getAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR);
            if (attribute != null) {
                requestPath = attribute.toString();
            }

            //返回描述此容器的名称字符串
            String servletName = wrapper.getName();

            //将相关的路径映射过滤器添加到此过滤器链
            for (int i = 0; i < filterMaps.length; i++) {
                //dispatcher类型与FilterMap中指定的dispatcher类型是否匹配
                if (!matchDispatcher(filterMaps[i], dispatcher)) {
                    continue;
                }
                //上下文相关的请求路径符合指定的筛选器映射的要求
                if (!matchFiltersURL(filterMaps[i], requestPath))
                    continue;
                //从上下文context中获取ApplicationFilterConfig
                ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
                        context.findFilterConfig(filterMaps[i].getFilterName());
                if (filterConfig == null) {
                    // FIXME - log configuration problem
                    continue;
                }
                //将过滤器添加到将在此链中执行的过滤器集中。
                filterChain.addFilter(filterConfig);
            }

            // 添加与servlet名称第二次匹配的过滤器
            for (int i = 0; i < filterMaps.length; i++) {
                //dispatcher类型与FilterMap中指定的dispatcher类型是否匹配
                if (!matchDispatcher(filterMaps[i], dispatcher)) {
                    continue;
                }
                //如果指定的servlet名称符合指定的筛选器映射的要求
                if (!matchFiltersServlet(filterMaps[i], servletName))
                    continue;
                //从上下文context中获取ApplicationFilterConfig
                ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
                        context.findFilterConfig(filterMaps[i].getFilterName());
                if (filterConfig == null) {
                    // FIXME - log configuration problem
                    continue;
                }
                //将过滤器添加到将在此链中执行的过滤器集中。
                filterChain.addFilter(filterConfig);
            }

最终过滤器加入了ApplicationFilterConfig数组的末尾。

执行过滤器链

    filterChain.doFilter(request.getRequest(), response.getResponse());

最终会调用到ApplicationFilterChain的internalDoFilter方法:

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

            // 如果有一个过滤器,调用下一个过滤器
            //pos:过滤器链中当前位置的索引。
            //n:链中过滤器当前数量
            if (pos < n) {
                //获取过滤器配置
                ApplicationFilterConfig filterConfig = filters[pos++];
                try {
                    //获取过滤器,会调用:filter.init
                    Filter filter = filterConfig.getFilter();

                    //异步处理
                    if (request.isAsyncSupported() && "false".equalsIgnoreCase(
                            filterConfig.getFilterDef().getAsyncSupported())) {
                        request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
                    }
                    //调用doFilter,处理完过滤逻辑之后还会继续调用当前过滤器链的doFilter方法
                    if (Globals.IS_SECURITY_ENABLED) {
                        final ServletRequest req = request;
                        final ServletResponse res = response;
                        Principal principal =
                                ((HttpServletRequest) req).getUserPrincipal();

                        Object[] args = new Object[]{req, res, this};
                        SecurityUtil.doAsPrivilege("doFilter", filter, classType, args, principal);
                    } else {
                        filter.doFilter(request, response, this);
                    }
                } catch (IOException | ServletException | RuntimeException e) {
                    throw e;
                } catch (Throwable e) {
                    e = ExceptionUtils.unwrapInvocationTargetException(e);
                    ExceptionUtils.handleThrowable(e);
                    throw new ServletException(sm.getString("filterChain.filter"), e);
                }
                return;
            }

            // We fell off the end of the chain -- call the servlet instance
            //准备调用servlet.service方法
            try {
                if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
                    lastServicedRequest.set(request);
                    lastServicedResponse.set(response);
                }

                if (request.isAsyncSupported() && !servletSupportsAsync) {
                    request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
                            Boolean.FALSE);
                }
                // Use potentially wrapped request from this point
                if ((request instanceof HttpServletRequest) &&
                        (response instanceof HttpServletResponse) &&
                        Globals.IS_SECURITY_ENABLED) {
                    final ServletRequest req = request;
                    final ServletResponse res = response;
                    Principal principal =
                            ((HttpServletRequest) req).getUserPrincipal();
                    Object[] args = new Object[]{req, res};
                    SecurityUtil.doAsPrivilege("service",
                            servlet,
                            classTypeUsedInService,
                            args,
                            principal);
                } else {
                    //执行业务逻辑
                    servlet.service(request, response);
                }
            } catch (IOException | ServletException | RuntimeException e) {
                throw e;
            } catch (Throwable e) {
                e = ExceptionUtils.unwrapInvocationTargetException(e);
                ExceptionUtils.handleThrowable(e);
                throw new ServletException(sm.getString("filterChain.servlet"), e);
            } finally {
                if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
                    lastServicedRequest.set(null);
                    lastServicedResponse.set(null);
                }
            }
        }

其中filter.doFilter,处理完过滤逻辑之后还会继续调用当前过滤器链的doFilter方法,直到所有过滤器链处理完毕。
最后执行Servlet的service方法,处理业务逻辑。

基本上将调用链的逻辑分析完了,下一篇简单的总结一下整个请求处理过程。


来源:https://www.jianshu.com/u/9632919f32c3

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » Tomcat源码分析【十六】请求处理过程分析之创建与执行过滤器链

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏