How to add a filter in Spring Boot

In this post, we will see how to add a filter in Spring Boot and what are the options to configure these filters in Spring Boot including specifying their innovation order.

1.How to add a filter in Spring Boot

Filters as the name suggest used to perform filtering on either the request to a resource or on the response from a resource, or both. Spring Boot provides few options to register custom filters in the Spring Boot application.Filters can perform the following operations.

  1. Pre-Processing Requests: We can use filters in Spring boot to preprocess the request before request is handed over to the controller. There are number of use cases which can be achieved using pre-processing like
    • Security – Can be used to perform security checks.
    • Logging and auditing – We can use these custom filters to do logging and audit for monitoring and debugging.
    • Data Validation – Before handing over the data to our controller, we can utilize these pre-processing filters to validate any request and headers data.
    • Content Negotiation: Can be effectively used for content negotiation.
  2. Post-processing – Processing response before it reaches the client. This is also a great place to do these additional work before response is sent back to the client.
    • Caching : For frequent used data, we can cache it in the post-processing filters to improve system performance.
    • Compression : We can compress the response using these filters, this is a common technique used to reduce network bandwidth.
    • Metrics and Monitoring.

1.1.Using Filter Interface

The most common way to add a custom filter in spring boot is through @Component annotation. Here is a sample code outlining a simple Servlet filter.

@Component
public class MyFilter implements Filter {
   @Override
   public void destroy() {}

   @Override
   public void doFilter
      (ServletRequest request, ServletResponse response, FilterChain filterchain) 
      throws IOException, ServletException {
          //place to perform request processing.
      }

   @Override
   public void init(FilterConfig filterconfig) throws ServletException {}
}

1.2. Use Abstract Filter

Another option is to use Spring built in filter class like OncePerRequestFilter. These are the helper classes designed to do some additional work for us like

  • Preventing multiple execution for a single request.
  • Maintaining state information for the request
Please go through the Spring documentation to understand what other feature these helper classes provides and its a good practice to use these classes than implementing Filter interface.
@Component
public class RequestLoggingFilter extends OncePerRequestFilter {

	@Override
	protected void doFilterInternal(HttpServletRequest request,
	    HttpServletResponse response,
	    FilterChain filterChain) throws ServletException, IOException {

	  //logic to record request logs
	  filterChain.doFilter(request, response);
	}
}

Let’s look at the different options to add filter in Spring Boot application.

2. Define Filter and Invocation Order

We need to Implement Filter interface to create a new filter in Spring Boot.

@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CustomFilter implements Filter {

    private static final Logger LOGGER = LoggerFactory.getLogger(CustomFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        LOGGER.info("########## Initiating Custom filter ##########");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        LOGGER.info("Logging Request  {} : {}", request.getMethod(), request.getRequestURI());

        //call next filter in the filter chain
        filterChain.doFilter(request, response);

        LOGGER.info("Logging Response :{}", response.getContentType());
    }

    @Override
    public void destroy() {
       LOGGER.info("########## Calling destroy method ##########");
    }
}

Let’s quickly look at some important points in the above code

  • The filter registered by @Component annotation.
  • To fire filters in the right order–we needed to use the @Order annotation.

The highest order filter run first. This is useful when we want to execute our custom filters on pre-defined order.

@Component
@Order(1)
public class CustomFirstFilter implements Filter {

}

@Component
@Order(2)
public class CustomSecondFilter implements Filter {

}

In the above code, CustomFirstFilter will run before the CustomSecondFilter.The lower the number, the higher the precedence

3. Filter based on URL Pattern

In above example, our filter were registered for all requests i.e. every request coming to our system will invoke our customer filter regardless if its needed or not/

In some cases you many want to apple the filter based on a certain URL pattern and not for every request. e.g. I want to apply my for all request with URL pattern as /greeting/**. How can I do that?

To run the filter for URL pattern, we can use FilterRegistrationBean. Don’t use @Component annotation for the filter class but register the filter using a FilterRegistrationBean.

public class CustomURLFilter implements Filter {

    private static final Logger LOGGER = LoggerFactory.getLogger(CustomURLFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        LOGGER.info("########## Initiating CustomURLFilter filter ##########");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        LOGGER.info("This Filter is only called when request is mapped for /customer resource");

        //call next filter in the filter chain
        filterChain.doFilter(request, response);
    }

    @Override
    public void destroy() {
      LOGGER.info("########## Calling destroy method ##########");
    }
}

Nest step is to tell spring boot when to invoke our custom filter, to do that we need to register the custom Filter using FilterRegistrationBean.

@Configuration
public class AppConfig {

   @Bean
   public FilterRegistrationBean < CustomURLFilter > filterRegistrationBean() {
      FilterRegistrationBean < CustomURLFilter > registrationBean = new FilterRegistrationBean();
      CustomURLFilter customURLFilter = new CustomURLFilter();

      registrationBean.setFilter(customURLFilter);
      registrationBean.addUrlPatterns("/greeting/*"); // setting the URL pattern when this filter will be invoked 
      registrationBean.setOrder(2); //set precedence
      return registrationBean;
   }
}

4. Using @WebFilter

The @WebFilter annotation is part of Servlet 3.0 spec. We can use the @WebFilter annotation to register our custom filter with the embedded servlet container. Keep in mind when using this annotation, you should remove the @Component annotation.

Use @WebFilter when you need precise control over URL patterns, filter execution order, and want to leverage Servlet container features.
@WebFilter
public class CustomFilter implements Filter {

    private static final Logger LOGGER = LoggerFactory.getLogger(CustomFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        LOGGER.info("########## Initiating Custom filter ##########");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        LOGGER.info("Logging Request  {} : {}", request.getMethod(), request.getRequestURI());

        //call next filter in the filter chain
        filterChain.doFilter(request, response);
        LOGGER.info("Logging Response :{}", response.getContentType());
    }

    @Override
    public void destroy() {
       
    }
}
@WebFilter(urlPatterns="/custom-filter/**")
public class CustomFilter implements Filter {

    private static final Logger LOGGER = LoggerFactory.getLogger(CustomFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        LOGGER.info("########## Initiating Custom filter ##########");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        filterChain.doFilter(request, response);
    }

    @Override
    public void destroy() {
       
    }
}

When using the @WebFilter annotation, make sure we add @ServletComponentScan annotation to enable scanning on @WebFilter

@ServletComponentScan
public class AppConfig { ...}

5. Demo

Let’s now create a simple spring mvc controller and send an HTTP request to it. In our demo , we will run 2 use cases

  • Call the base url like “/” and it will invoke all the filters in given order.
  • Call /greeting endpoint to see some specific filters are being triggered.
@RestController
public class FilterExampleController {

 @GetMapping
 public String greeting() {
  return "Hello World";
 }

 @GetMapping(value = "/greeting")
 public String customGreetings() {
  return "Hello From Custom Greetings";
 }
}

When we start and run our application, following logs can be found in the console.

####################################################################  On Server startup ####################################################################
2018-07-04 17:22:32.221  INFO 40519 --- [ost-startStop-1] c.j.filters.CustomURLFilter              : ########## Initiating CustomURLFilter filter ##########
2018-07-04 17:22:32.222  INFO 40519 --- [ost-startStop-1] com.javadevjournal.filters.CustomFilter  : ########## Initiating Custom filter ##########


################################################################### On Hitting http://host:port/ ##############################################################
2018-07-04 17:22:56.710  INFO 40519 --- [nio-8080-exec-1] com.javadevjournal.filters.CustomFilter  : Logging Request  GET : /
2018-07-04 17:22:56.743  INFO 40519 --- [nio-8080-exec-1] com.javadevjournal.filters.CustomFilter  : Logging Response :text/html;charset=UTF-8


################################################################### On Hitting http://host:port/greeting #######################################################
2018-07-04 17:24:42.325  INFO 40519 --- [nio-8080-exec-5] com.javadevjournal.filters.CustomFilter  : Logging Request  GET : /greeting
2018-07-04 17:24:42.325  INFO 40519 --- [nio-8080-exec-5] c.j.filters.CustomURLFilter              : This Filter is only called when request is mapped for /customer resource
2018-07-04 17:24:42.327  INFO 40519 --- [nio-8080-exec-5] com.javadevjournal.filters.CustomFilter  : Logging Response :text/html;charset=UTF-8

6. Disabling Filter

Spring Boot also provide the option to disable the registered filter in case we need it. Use the FilterRegistrationBean‘s setEnabled(false) method.

@Bean
public FilterRegistrationBean registration(AuditFilter filter) {
    FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
    registrationBean.setEnabled(false);
    return registrationBean;
}

Summary

In this post, we explore how to add a filter in Spring Boot. We covered the different options for creating and registering the custom filter in our Spring Boot application along with how to disable filter in case needed. We can find code snippets GitHub

4 thoughts on “How to add a filter in Spring Boot”

Comments are closed.