banner
田野放空

田野放空

认真扮演一个擅长白日做梦的普通人

java 中filter的执行顺序是怎样的

问题:#

  1. filterChain 是什么时候执行的呢?
  2. filterChain 中的 filter 来源何处?
  3. standardContext 什么时候开始收集的过滤器集合

1. filterChain 是什么时候执行的呢?#

org.apache.catalina.core.StandardWrapperValve 类中有如下一个方法

public final void invoke(Request request, Response response)
        throws IOException, ServletException {

				//省略掉大段无关代码
        Servlet servlet = null;
        Context context = (Context) wrapper.getParent();
				//省略掉大段无关代码
        try {
            if (!unavailable) {
              	//1.create servlet
                servlet = wrapper.allocate();
            }
        } catch(){
          ...
        }
        // 2. Create the filter chain for this request
        ApplicationFilterChain filterChain =
                ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);

        Container container = this.container;
        try {
            if ((servlet != null) && (filterChain != null)) {
                // Swallow output if needed
                if (context.getSwallowOutput()) {
                    try {
                        SystemLogHandler.startCapture();
                        if (request.isAsyncDispatching()) {
                            request.getAsyncContextInternal().doInternalDispatch();
                        } else {
                          	//execute doFilter method of the FilterChain object.
                            filterChain.doFilter(request.getRequest(),
                                    response.getResponse());
                        }
                    } finally {
                      
                    }
                } else {
                    if (request.isAsyncDispatching()) {
                        request.getAsyncContextInternal().doInternalDispatch();
                    } else {
                        filterChain.doFilter
                            (request.getRequest(), response.getResponse());
                    }
                }

            }
        } catch(){
        } finally {
            // Release the filter chain (if any) for this request
            if (filterChain != null) {
                filterChain.release();
            }

            // Deallocate the allocated servlet instance
            try {
                if (servlet != null) {
                    wrapper.deallocate(servlet);
                }
            }
        }
    }


我们一会儿回过头来看它是如何创建过滤器链对象的代码,我们先来看他是如何执行过滤器链的,过滤器链对象执行的流程实现:

public final class ApplicationFilterChain implements FilterChain {
   //cur executing filter index
   private int pos = 0;
  //matched filter count 
   private int n = 0;
  //servlet 
   private Servlet servlet = null;
  //matched filter arrays
   private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];

  @Override
  public void doFilter(ServletRequest request, ServletResponse response)
        throws IOException, ServletException {

    		//security been turned on
        if( Globals.IS_SECURITY_ENABLED ) {
          //... security bean filter
        } else {
          	//execute filter logic 
            internalDoFilter(request,response);
        }
    }

    private void internalDoFilter(ServletRequest request,
                                  ServletResponse response)
        throws IOException, ServletException {
      
      	// loop and  Call the next filter if there is one
        if (pos < n) {
          	//pos index ++
            ApplicationFilterConfig filterConfig = filters[pos++];
            try {
                Filter filter = filterConfig.getFilter();
                if( Globals.IS_SECURITY_ENABLED ) {
                } else {
                  	//execute the doFilter() of the cur filter in the filter chain
                    filter.doFilter(request, response, this);
                }
            } catch(){
              ...
            }
            return;
        }

        // We fell off the end of the chain -- call the servlet instance
        try {
            if ((request instanceof HttpServletRequest) &&
                    (response instanceof HttpServletResponse) &&
                    Globals.IS_SECURITY_ENABLED ) {
            } else {
              	//if there are no filters to be executed, the servlet's service method will be executed, which 									contains the business logic that we have written.
                servlet.service(request, response);
            }
        }catch(){
          ...
        }finally{
          ...
        }
    }
}

从 filterChain 类的源码可以看出底层是包含了 所匹配上的 filter 数组 也就是添加进去匹配上过滤器对象是有序的,添加的时候就决定了。

那么它是什么时候添加的呢?

2. filterChain 中的 filter 来源何处?#

其实在org.apache.catalina.core.StandardWrapperValve 类的 invoke 方法中

ApplicationFilterChain filterChain =
               ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
    public static ApplicationFilterChain createFilterChain(ServletRequest request,
            Wrapper wrapper, Servlet servlet) {

        // If there is no servlet to execute, return null
        if (servlet == null)
            return null;

        // Create and initialize a filter chain object
        ApplicationFilterChain filterChain = null;
        if (request instanceof Request) {
            Request req = (Request) request;
            if (Globals.IS_SECURITY_ENABLED) {
                // Security: Do not recycle
                filterChain = new ApplicationFilterChain();
            } else {
                filterChain = (ApplicationFilterChain) req.getFilterChain();
                if (filterChain == null) {
                    filterChain = new ApplicationFilterChain();
                    req.setFilterChain(filterChain);
                }
            }
        } else {
            // Request dispatcher in use
            filterChain = new ApplicationFilterChain();
        }

        filterChain.setServlet(servlet);
        filterChain.setServletSupportsAsync(wrapper.isAsyncSupported());

        // Acquire the filter mappings for this Context
        StandardContext context = (StandardContext) wrapper.getParent();
      	//Get an array of all the filters registered in the ServletContext object
        FilterMap filterMaps[] = context.findFilterMaps();

        // If there are no filter mappings, we are done
        if ((filterMaps == null) || (filterMaps.length == 0))
            return filterChain;

        // Acquire the information we will need to match filter mappings
        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();

        // Add the relevant path-mapped filters to this filter chain
        for (int i = 0; i < filterMaps.length; i++) {
            if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
                continue;
            }
            if (!matchFiltersURL(filterMaps[i], requestPath))
                continue;
            ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
                context.findFilterConfig(filterMaps[i].getFilterName());
            if (filterConfig == null) {
                // FIXME - log configuration problem
                continue;
            }
            filterChain.addFilter(filterConfig);
        }

        // Add filters that match on servlet name second
        for (int i = 0; i < filterMaps.length; i++) {
            if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
                continue;
            }
            if (!matchFiltersServlet(filterMaps[i], servletName))
                continue;
            ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
                context.findFilterConfig(filterMaps[i].getFilterName());
            if (filterConfig == null) {
                // FIXME - log configuration problem
                continue;
            }
            filterChain.addFilter(filterConfig);
        }

        // Return the completed filter chain
        return filterChain;
    }

​ 可以看出在创建 filterChain 对象时候,从 ServletContext 获取所有注册的 filter 的数组取出需要的添加到这次请求创建的 filterChain 对象,而且 servletContext 对象的注册的所有的过滤器本身就是一个数组(本身就是有序的), 所以遍历匹配的时候,也就是有序的。

3. ServletContext 什么时候开始收集的数组#

filterMaps 在 StandardContext 类中

public class StandardContext extends ContainerBase
        implements Context, NotificationEmitter {

  private final ContextFilterMaps filterMaps = new ContextFilterMaps();
  
  //
  @Override
    public void addFilterMap(FilterMap filterMap) {
        validateFilterMap(filterMap);
        // Add this filter mapping to our registered set
        filterMaps.add(filterMap);
        fireContainerEvent("addFilterMap", filterMap);
    }

}

启动 tomcat,我们可以根据堆栈查看调用顺序

StandardContext.startInternal()-->fireLifecycleEvent()-->ContextConfig.lifecycleEvent()-->ContextConfig.lifecycleEventcon-->ContextConfig.con.figureStart()-->ContextConfig.webConfig()

查看方法

protected void webConfig() {
      if (ok) {
          configureContext(webXml);
      }
}

private void configureContext(WebXml webxml) {
      for (FilterMap filterMap : webxml.getFilterMappings()) {
          context.addFilterMap(filterMap);
      }
}

这里就将 web.xml 收集到所有 filter 的 set 集合,然后将收集到的 filter 集合转换成数组,设置给 StandardContext 对象

加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。