MTI TEK
  • Home
  • About
  • LLMs
  • Docker
  • Kubernetes
  • Java
  • All Resources
Java Servlet | Filter
  1. Introduction to Servlet Filters
  2. Filter Lifecycle and Execution
    1. Loading the Filter Class into Memory
    2. Instantiating the Filter Class
    3. Calling the init() Method
    4. Calling the doFilter() Method
    5. Calling the destroy() Method
  3. Deployment Descriptor Configuration
  4. Filter Chain Execution Order
  5. Filter Initialization Parameters

  1. Introduction to Servlet Filters
    Servlet filters are components that sit between the client and the servlet, intercepting HTTP requests and responses. They are executed by the servlet container upon receiving an HTTP request that matches specific patterns defined in the web.xml deployment descriptor.

    Filters operate as part of a filter chain, where each filter has the opportunity to process the request before passing control to the next filter or servlet. This design pattern allows for separation of concerns and modular request processing.

    The primary characteristics of servlet filters include:
    • They execute before servlets in the request processing chain.
    • They can modify request and response objects.
    • They can short-circuit the filter chain by not calling the next filter.
    • They are responsible for passing control to the next component in the chain.

    Filters are mainly used to intercept an HTTP request and perform some processing before the execution of the target resource (typically a Servlet or JSP page) and/or before the response is sent back to the client.
                     HTTP request                   doFilter                   doFilter                   doFilter
         +--------+ ==============> +------------+ ==========> +------------+ ==========> +------------+ ==========> +-------------+
         | Client |                 | Filter (1) |             | Filter (2) |             | Filter (3) |             | Servlet (1) |
         +--------+ <============== +------------+ <========== +------------+ <========== +------------+ <========== +-------------+
                      HTTP response
    In the above example:
    • A client (typically a browser) sends an HTTP request targeting Servlet (1).
    • The servlet container recognizes that there are three filters that match the request pattern.
    • These filters are executed in the order in which they are defined in the deployment descriptor.
    • Each executed filter decides whether or not to pass control to the next resource (filter or Servlet) by calling filterChain.doFilter().
    • Once the last resource (filter or Servlet) has executed, control is returned to the previous resources in reverse order, allowing filters to perform post-processing of the response.
    • This reverse execution happens automatically as the JVM returns to the calling method in the call stack and continues code execution back to the original caller.
  2. Filter Lifecycle and Execution
    The servlet filter lifecycle consists of five distinct phases, each managed by the servlet container.
    1. Loading the Filter Class into Memory
      The filter class loading phase occurs when the servlet container determines that a filter needs to be available for request processing. The timing of this phase is flexible and depends on the container implementation and configuration.

      A filter class may be loaded into memory:
      • when the servlet container starts up (eager loading).
      • when the web application is deployed or redeployed.
      • upon receiving the first request that requires the filter to run (lazy loading).
      • or at any moment between container startup and the first relevant request.

      If no special configuration such as load-on-startup is provided, the servlet container alone decides when to load the filter class. This decision is typically based on memory optimization and application startup performance considerations.

      After the class is loaded into the JVM's method area:
      • all static fields of the class will be initialized with their default or assigned values (example: static String myVar1 = "default";).
      • all static initialization blocks will be executed in the order they appear in the class (example: static { /* initialization code */ }).
      • the class becomes available for instantiation.
    2. Instantiating the Filter Class
      Filter instantiation occurs when the servlet container decides to create a filter instance. This typically happens right after the class is loaded, but the container may choose to delay instantiation until the filter is actually needed for request processing.

      The servlet container typically creates only one instance of each filter class per web application, following the singleton pattern. This single instance handles all requests that match the filter's configuration.

      During the instantiation process:
      • all instance fields of the class will be initialized with their default or assigned values.
      • all instance initialization blocks will be executed in the order they appear in the class.
      • the no-argument constructor (if defined) will be invoked to complete the object creation.

      Important Note: If a no-argument constructor is not explicitly defined in the filter class, the Java compiler will automatically provide a default no-argument constructor, provided the class does not declare any constructor with parameters. If you define any parameterized constructor, you must explicitly provide a no-argument constructor for the servlet container to instantiate the filter.
    3. Calling the init() Method
      The init(FilterConfig filterConfig) method is called immediately after the filter instance is created. This method is called exactly once during the filter's lifetime and serves as the initialization phase where the filter can prepare itself for handling requests.

      The FilterConfig parameter provides access to the filter's configuration information, including initialization parameters and the servlet context. It is a common practice to store the FilterConfig instance in an instance variable so that it can be accessed later in the doFilter method for retrieving initialization parameters or accessing the servlet context.

      This method is ideal for performing one-time initialization tasks such as reading configuration files, establishing database connections, or setting up resources that will be used throughout the filter's lifetime.

      If the init() method throws a ServletException, the filter will not be put into service, and the container will not route any requests to this filter.
    4. Calling the doFilter() Method
      The doFilter(ServletRequest request, ServletResponse response, FilterChain chain) method is the core of filter functionality. It is executed each time a new request is intercepted by the filter, making it the most frequently called method during the filter's lifetime.

      This method receives three parameters:
      • ServletRequest request: contains the client's request data.
      • ServletResponse response: used to send data back to the client.
      • FilterChain chain: represents the remaining filters and the target servlet.

      The FilterChain parameter is crucial for maintaining the filter chain execution. By calling chain.doFilter(request, response), the filter passes control to the next filter in the chain, or to the target servlet if this is the last filter.

      If a filter does not call chain.doFilter(), the request processing chain stops at that filter, and no subsequent filters or the target servlet will be executed. In this case, the filter is responsible for generating a complete response to send back to the client.

      Filters can perform processing both before and after calling chain.doFilter(), allowing them to modify the request before it reaches the servlet and modify the response after the servlet has processed it.
    5. Calling the destroy() Method
      The destroy() method is called when the servlet container decides that a filter instance is no longer needed and should be removed from service. This method provides an opportunity for the filter to clean up any resources it may be holding.

      The timing of the destroy() method call can vary:
      • when the servlet container is shutting down.
      • when the web application is being stopped or undeployed.
      • when the container decides to destroy the instance to free memory.
      • during application redeployment.

      This method should be used to release resources such as database connections, file handles, threads, or any other system resources that were acquired during the filter's initialization or operation. Proper cleanup in the destroy() method helps prevent memory leaks and resource exhaustion.

      After destroy() is called, the filter instance will not receive any more requests, and the container may garbage collect the instance.
    Filter Implementation Example:
    package com.mtitek.filters.test1;
    
    import java.io.IOException;
    
    import jakarta.servlet.Filter;
    import jakarta.servlet.FilterChain;
    import jakarta.servlet.FilterConfig;
    import jakarta.servlet.ServletException;
    import jakarta.servlet.ServletRequest;
    import jakarta.servlet.ServletResponse;
    
    public class MyFilter1 implements Filter {
        FilterConfig filterConfig;
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            this.filterConfig = filterConfig;
            System.out.println("com.mtitek.filters.test1.MyFilter1 - " + this.filterConfig.getFilterName() + " : init(FilterConfig)");
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            System.out.println("com.mtitek.filters.test1.MyFilter1 - " + this.filterConfig.getFilterName() + " : doFilter(ServletRequest, ServletResponse, FilterChain) : Start");
    
            filterChain.doFilter(servletRequest, servletResponse);
    
            System.out.println("com.mtitek.filters.test1.MyFilter1 - " + this.filterConfig.getFilterName() + " : doFilter(ServletRequest, ServletResponse, FilterChain) : End");
        }
    
        @Override
        public void destroy() {
            System.out.println("com.mtitek.filters.test1.MyFilter1 - " + this.filterConfig.getFilterName() + " : destroy()");
        }
    }
    The FilterConfig interface provides the following essential methods:
    • String getFilterName(): returns the logical name of the filter as defined in the deployment descriptor.
    • ServletContext getServletContext(): returns a reference to the ServletContext, providing access to the application scope and container information.
    • String getInitParameter(String name): returns the value of the specified initialization parameter, or null if the parameter does not exist.
    • Enumeration<String> getInitParameterNames(): returns an Enumeration containing the names of all initialization parameters for this filter.
  3. Deployment Descriptor Configuration
    Filter configuration in the deployment descriptor (web.xml) involves two main elements that work together to define when and how filters are executed. The servlet container uses these configurations to determine which filters to apply to incoming requests.

    Filters are executed by the servlet container when an HTTP request matches one of the patterns defined in the deployment descriptor. The configuration consists of filter definitions and filter mappings that establish the relationship between filters and the requests they should process.

    The two primary elements for configuring filters are <filter> and <filter-mapping>. When processing a request, if the container finds a matching <filter-mapping> element, it will look for the corresponding <filter> element with the same filter name to determine which filter class to execute.
    • The <filter-mapping> Element

      The filter mapping element defines when a filter should be executed by specifying URL patterns or servlet names that trigger the filter.
      <filter-mapping>
          <filter-name> <!-- exactly one -->
          <url-pattern> OR <servlet-name> <!-- exactly one -->
          <dispatcher> <!-- [0 to 4] {REQUEST, FORWARD, INCLUDE, ERROR} -->
      • <filter-name>: The logical name that identifies the filter. This name must exactly match the name specified in the corresponding <filter> element. This creates the link between the filter mapping and the actual filter implementation.

      • <url-pattern>: When specified, the filter will be executed for HTTP requests whose URLs match this pattern. URL patterns can use wildcards such as /* (matches all URLs), /admin/* (matches all URLs starting with /admin/), or *.jsp (matches all JSP files). You cannot specify both <url-pattern> and <servlet-name> in the same mapping.

      • <servlet-name>: When specified, the filter will be executed whenever a request is processed by the servlet with this name. The servlet name refers to the <servlet-name> element within a <servlet> declaration. This approach allows filtering specific servlets regardless of their URL mapping.

      • <dispatcher>: This optional element controls the type of request dispatch that will trigger the filter execution. Understanding dispatcher types is crucial for complex web applications that use request forwarding and including.

        The four possible dispatcher values are:
        • REQUEST (default value): The filter executes for normal HTTP requests from external clients (browsers, HTTP clients, etc.). This is the most common type of request processing.

        • FORWARD: The filter executes for requests that result from a server-side forward operation, triggered by calling the forward() method of the RequestDispatcher class. This is used when one servlet forwards a request to another servlet or JSP.

        • INCLUDE: The filter executes for requests that result from a server-side include operation, triggered by calling the include() method of the RequestDispatcher class. This is used when including the output of another servlet or JSP in the current response.

        • ERROR: The filter executes for internal requests that target error pages specified in <error-page> elements. This allows filters to process error handling requests.

        Multiple dispatcher types can be configured by including multiple <dispatcher> elements in the same filter mapping. This enables the filter to handle different types of request processing scenarios.
    • The <filter> Element

      The filter element defines the actual filter implementation and its configuration parameters.
      <filter>
          <description> <!-- 0 or more -->
          <display-name> <!-- 0 or more -->
          <icon> <!-- 0 or more -->
              <small-icon> <!-- 0 or 1 -->
              <large-icon> <!-- 0 or 1 -->
          <filter-name> <!-- exactly one -->
          <filter-class> <!-- exactly one -->
          <init-param> <!-- 0 or more -->
              <description> <!-- 0 or 1 -->
              <param-name> <!-- exactly one -->
              <param-value> <!-- exactly one -->
      Key elements include:
      • <filter-name>: The logical name of the filter that must exactly match the corresponding name in the <filter-mapping> element. This name is also accessible programmatically through the FilterConfig.getFilterName() method.

      • <filter-class>: The fully qualified class name of the filter implementation. This class must implement the jakarta.servlet.Filter interface and be available in the web application's classpath.

      • <init-param>: Optional initialization parameters that can be accessed by the filter through the FilterConfig object. These parameters allow configuration of filter behavior without modifying the filter's source code.
  4. Filter Chain Execution Order
    Understanding filter execution order is crucial for building complex web applications where multiple filters need to work together in a predictable sequence. The servlet container determines the execution order based on the deployment descriptor configuration and specific matching rules.

    A filter is executed when an HTTP request matches either a <url-pattern> in a filter mapping or when it matches the configuration of a servlet whose name is specified in a <servlet-name> element. Multiple filters may match the same HTTP request, creating a filter chain.

    The servlet specification defines a specific order for filter execution when multiple filters match a request:
    • URL Pattern Matching Filters Execute First
      Filters with matching <url-pattern> elements are executed before filters with matching <servlet-name> elements. Within this group, the execution order is determined by the sequence of <filter-mapping> elements as they appear in the deployment descriptor.

    • Servlet Name Matching Filters Execute Second
      After all URL pattern matching filters have been processed, filters with matching <servlet-name> elements are executed. Again, their execution order follows the order of <filter-mapping> declarations in the deployment descriptor.

    Practical Example:
    Consider the following filter mappings in web.xml and an HTTP request to http://localhost:8181/test/MyServlet1:
    <filter-mapping>
        <filter-name>MyFilter1</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>MyFilter3</filter-name>
        <servlet-name>MyServlet1</servlet-name>
    </filter-mapping>
    <filter-mapping>
        <filter-name>MyFilter2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    The execution order will be: MyFilter1 → MyFilter2 → MyFilter3 → MyServlet1

    Explanation:
    1. MyFilter1 executes first because it has a matching URL pattern (/*) and appears first among URL pattern mappings
    2. MyFilter2 executes second because it also has a matching URL pattern and appears second among URL pattern mappings
    3. MyFilter3 executes third because it matches by servlet name (MyServlet1), and servlet name mappings execute after URL pattern mappings
    4. Finally, MyServlet1 executes as the target resource

    This predictable ordering allows developers to design filter chains where filters depend on the processing performed by previous filters in the chain.
  5. Filter Initialization Parameters
    Initialization parameters provide a powerful mechanism for configuring filter behavior without hardcoding values into the filter implementation. These parameters are defined in the deployment descriptor and are available to the filter through the FilterConfig object passed to the init() method.

    Accessing Initialization Parameters:
    The FilterConfig interface provides two methods for working with initialization parameters:
    String getInitParameter(String parameterName)
    
    Enumeration<String> getInitParameterNames()
    The getInitParameter() method returns the value of the specified parameter, or null if the parameter does not exist. The getInitParameterNames() method returns an enumeration of all parameter names, which is useful for iterating through all available parameters.

    Declaring Parameters in web.xml:
    Initialization parameters are declared within the <filter> element using <init-param> sub-elements:
    <init-param>
        <param-name>PARAM_NAME</param-name>
        <param-value>PARAM_VALUE</param-value>
    </init-param>
    Each <init-param> element defines a name-value pair that will be available to the filter during its initialization and execution phases.

    Configuration and Implementation Example:
    • web.xml Configuration:
      <filter>
          <filter-name>MyFilter1</filter-name>
          <filter-class>com.mtitek.filters.test1.MyFilter1</filter-class>
          <init-param>
              <param-name>filter1_paramname_1</param-name>
              <param-value>filter1_paramvalue_1</param-value>
          </init-param>
          <init-param>
              <param-name>filter1_paramname_2</param-name>
              <param-value>filter1_paramvalue_2</param-value>
          </init-param>
      </filter>

    • Filter Implementation (MyFilter1.java):
      package com.mtitek.filters.test1;
      
      import java.io.IOException;
      import java.util.Enumeration;
      
      import jakarta.servlet.Filter;
      import jakarta.servlet.FilterChain;
      import jakarta.servlet.FilterConfig;
      import jakarta.servlet.ServletException;
      import jakarta.servlet.ServletRequest;
      import jakarta.servlet.ServletResponse;
      
      public class MyFilter1 implements Filter {
          FilterConfig filterConfig;
      
          @Override
          public void init(FilterConfig filterConfig) throws ServletException {
              this.filterConfig = filterConfig;
          }
      
          @Override
          public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
              Enumeration<String> initParameterNames = this.filterConfig.getInitParameterNames();
              while (initParameterNames.hasMoreElements()) {
                  String initParameterName = (String) initParameterNames.nextElement();
                  String initParameterValue = this.filterConfig.getInitParameter(initParameterName);
                  System.out.println(initParameterName + " : " + initParameterValue);
              }
      
              filterChain.doFilter(servletRequest, servletResponse);
          }
      
          @Override
          public void destroy() {
          }
      }

    • Expected Console Output:
      filter1_paramname_1 : filter1_paramvalue_1
      filter1_paramname_2 : filter1_paramvalue_2
© 2025 mtitek