SoFunction
Updated on 2025-03-08

Detailed explanation of the execution process of Filter in Tomcat

Preface

What is Filter? Filter is a java web component defined in the servlet specification. It can be used in all containers that support java web. It is a series of filters located between front-end requests and servlets. It can also be called middleware. It mainly does some extra actions before the request reaches the servlet:

  • 1. Permission control
  • 2. Monitoring
  • 3. Log management
  • 4. Wait

There are two interfaces involved: Filter and FilterChain

Filter and FilterChain are inseparable. Filter can be called in sequence precisely because of FilterChain.

1. Filter interface

public interface Filter {
   // Called when the container is created, that is, called when the tomcat is started   public void init(FilterConfig filterConfig) throws ServletException;
   // Called by FilterChain, and passed into FilterChain itself, and finally call back the doFilter() method of FilterChain   public void doFilter(ServletRequest request, ServletResponse response,
       FilterChain chain) throws IOException, ServletException;
   // Called when the container is destroyed, that is, call when the tomcat is closed   public void destroy();
 }

2. FilterChain interface

public interface FilterChain {
   // Called in ()   public void doFilter(ServletRequest request, ServletResponse response)
     throws IOException, ServletException;
}

Execution process

In the previous article, we know that tomcat startup will executeClassicinvokemethod:

public final void invoke(Request request, Response response){
  ......
  MessageBytes requestPathMB = ();
  DispatcherType dispatcherType = ;
  if (()==) dispatcherType = ;
  (Globals.DISPATCHER_TYPE_ATTR,dispatcherType);
  (Globals.DISPATCHER_REQUEST_PATH_ATTR,
      requestPathMB);
  // Create the filter chain for this request
  ApplicationFilterChain filterChain =
      (request, wrapper, servlet);
  // Call the filter chain for this request
  // NOTE: This also calls the servlet's service() method
  Container container = ;
  try {
    if ((servlet != null) && (filterChain != null)) {
      // Swallow output if needed
      if (()) {
        try {
          ();
          if (()) {
            ().doInternalDispatch();
          } else {
            ((),
                ());
          }
        } finally {
          String log = ();
          if (log != null && () > 0) {
            ().info(log);
          }
        }
      } else {
        if (()) {
          ().doInternalDispatch();
        } else {
          
            ((), ());
        }
      }
    }
  } catch (ClientAbortException | CloseNowException e) {
  }
  ......
}

The above code does the following actions:

  • 1. Each time a request comes, a filter chain will be created and the servlet object to be executed will be stored in the filter chain. For each url, the corresponding number of filters is not fixed. The filterchain needs to save a filter array corresponding to each request and the position of the filter called in order to continue calling the filter downward.
  • 2. After creating filterChain, doFilter starts to perform chain processing of requests.

1. Create filterChain

Let's take a look at how filterChain is created

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) ();
      if (filterChain == null) {
        filterChain = new ApplicationFilterChain();
        (filterChain);
      }
    }
  } else {
    // Request dispatcher in use
    filterChain = new ApplicationFilterChain();
  }
  (servlet);
  (());
  // Acquire the filter mappings for this Context
  StandardContext context = (StandardContext) ();
  FilterMap filterMaps[] = ();
  // If there are no filter mappings, we are done
  if ((filterMaps == null) || ( == 0))
    return filterChain;
  // Acquire the information we will need to match filter mappings
  DispatcherType dispatcher =
      (DispatcherType) (Globals.DISPATCHER_TYPE_ATTR);
  String requestPath = null;
  Object attribute = (Globals.DISPATCHER_REQUEST_PATH_ATTR);
  if (attribute != null){
    requestPath = ();
  }
  String servletName = ();
  // Add the relevant path-mapped filters to this filter chain
  for (FilterMap filterMap : filterMaps) {
    if (!matchDispatcher(filterMap, dispatcher)) {
      continue;
    }
    if (!matchFiltersURL(filterMap, requestPath))
      continue;
    ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
        (());
    if (filterConfig == null) {
      // FIXME - log configuration problem
      continue;
    }
    (filterConfig);
  }
  // Add filters that match on servlet name second
  for (FilterMap filterMap : filterMaps) {
    if (!matchDispatcher(filterMap, dispatcher)) {
      continue;
    }
    if (!matchFiltersServlet(filterMap, servletName))
      continue;
    ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
        (());
    if (filterConfig == null) {
      // FIXME - log configuration problem
      continue;
    }
    (filterConfig);
  }
  // Return the completed filter chain
  return filterChain;
}

The above code does a few things:

  • 1. Store the servlet to be executed in the filter chain.
  • 2. If no filter is configured, return an empty filter chain (only the servlet set above).
  • 3. If you configure the url-pattern filter, add the matching filter to the filter chain.
  • 4. If you configure the servlet-name filter, add the matching filter to the filter chain.

Note: The order () is consistent with the order of Filters defined in it, so the execution order of the filters is determined in the upper and lower order of the defined.

2. Execute dofilter

After creating the chain, the chain request is started. The specific logic is as follows:

private void internalDoFilter(ServletRequest request,
                                  ServletResponse response)
        throws IOException, ServletException {
  // Call the next filter if there is one
  if (pos < n) {
    ApplicationFilterConfig filterConfig = filters[pos++];
    try {
      Filter filter = ();
      if (() && "false".equalsIgnoreCase(
          ().getAsyncSupported())) {
        (Globals.ASYNC_SUPPORTED_ATTR, );
      }
      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};
         ("doFilter", filter, classType, args, principal);
      } else {
        (request, response, this);
      }
    } catch (IOException | ServletException | RuntimeException e) {
      throw e;
    } catch (Throwable e) {
      e = (e);
      (e);
      throw new ServletException((""), e);
    }
    return;
  }
  // We fell off the end of the chain -- call the servlet instance
  try {
    if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
      (request);
      (response);
    }
    if (() && !servletSupportsAsync) {
      (Globals.ASYNC_SUPPORTED_ATTR,
          );
    }
    // 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};
      ("service",
                     servlet,
                     classTypeUsedInService,
                     args,
                     principal);
    } else {
      (request, response);
    }
  } catch (IOException | ServletException | RuntimeException e) {
    throw e;
  } catch (Throwable e) {
    e = (e);
    (e);
    throw new ServletException((""), e);
  } finally {
    if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
      (null);
      (null);
    }
  }
}

The above code logic is as follows:

  • 1. Use the position index to determine whether all filters have been executed
  • 2. If not, take out the currently-to-execute filter and call its doFilter method. In the interface description above, we see that all filter classes inherit the filter interface and implement the dofilter method; we also noticed that this method receives a filterChain object. In this code,(request, response, this);You can see that if you pass your own reference in, then in the dofilter method, each filter can determine whether it is necessary to continue the following filter chain execution based on its own business needs. If necessary, execute it.Method, now it returns to this code. If repeated
  • 3. If all filters are executed, start executing the servlet business module.(request, response);

The above is a detailed explanation of how Filter is executed in Tomcat. For more information on the execution of Tomcat Filter, please follow my other related articles!