Using Filters in Spring Web Applications

Using Filters in Spring Web Applications

0 Comments

Spring Web applications and RESTful services contain controllers responsible to process requests and send back responses. At times you might need to perform certain operations on client requests before it reaches the controller. Similarly, you might need to perform operations on responses sent back by controllers to clients. You can achieve this using filters in Spring Web applications.

Filters are implementations of the Filter interface of Java EE. Spring brings in its own filter implementation with the GenericFilterBean abstract class.

Some of the common use cases of filters are:

  • Logging requests and response
  • Logging request processing time
  • Formatting of request body or header
  • Verifying authentication tokens
  • Compressing response
  • Performing Image conversions

In this post, you will learn how to configure filters in Spring Boot applications.

Filter Interface Methods

The Filter Interface contains the following three methods:

  • init(): The web container calls this method to indicate to a filter that it is being placed into service. The container calls this method only once. during the lifecycle of the filter instance. The init() method must complete successfully before the filter is asked to do any filtering work. The  web container cannot place the filter into service if the init() method either:
    • Throws a ServletException
    • Does not return within a time period defined by the web container
  • doFilter(): The Web container invokes this method every time whenever the client sends a request or the application sends back a response. It is in this method where you perform operation on the request and response objects.
  • destroy(): The Web container calls this method to indicate to a filter that it is being taken out of service. The container calls this method only once during the lifecycle of the filter instance. This method gives the filter an opportunity to clean up any resources that are being held. For example, memory, file handles, and threads.

Note: The GenericFilterBean abstract class of Spring implements the Filter interface. The class leaves actual filtering to subclasses, which have to implement the doFilter() method.

Filter Example

This example demonstrates configuring filters in Spring Web applications.

Maven Dependency

For this demo, you will need the spring-boot-starter-web and lombok dependencies in your pom.xml.

pom.xml

	<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.18.20</version>
		</dependency>

The Domain Class

The code of the MemeMaker domain class is this.

Mememaker.java

@Getter
@Setter
public class MemeMaker {
    private int memeId;
    private String memeMaker;
    private String memeTopic;
    private String memeLevel;

}

The preceding code uses Lombok to reduce boilerplate code. If you are new to Lombok, I suggest going through my post on Lombok.

This is code for the MemeController class.

MemeController.java

@RestController
@RequestMapping("/meme")
public class MemeController {
    @GetMapping
    @ResponseBody
    public MemeMaker getMemeMakerDetails() {
        MemeMaker memeMaker = new MemeMaker();
        memeMaker.setMemeId(1);
        memeMaker.setMemeMaker("Alex");
        memeMaker.setMemeLevel("Noobie");
        memeMaker.setMemeTopic("Trending");
        return memeMaker;
    }
}

The preceding code annotates the controller class with @RestController. It has one handler method getMemeMakerDetails() for GET request. This method returns a MemeMaker object.

The Filter Class

The next step is to create a filter, like this

MemeFilter.java

package guru.springframework.springfilter.filter;

import ch.qos.logback.classic.Level;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

@Component
@Slf4j
public class MemeFilter implements Filter {

@Override
public void init(FilterConfig filterConfig) {
    log.debug("init() method has been get invoked");
    log.debug("Filter name is "+filterConfig.getFilterName());
    log.debug("ServletContext name is"+filterConfig.getServletContext());
    log.debug("init() method is ended");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
  log.debug("doFilter() method is invoked");
  HttpServletRequest httpServletRequest = (HttpServletRequest)servletRequest;
  HttpServletResponse httpServletResponse = (HttpServletResponse)servletResponse;
  filterChain.doFilter(httpServletRequest, httpServletResponse);
  log.debug("doFilter() method is ended");
}
@Override
public void destroy() {
  log.debug("destroy() method is invoked");
}
}

The preceding code creates a filter class named MemeFilter that implements the Filter interface. The code annotates the class with @Component so that Spring detects it during component scanning. In addition, the MemeFilter class overrides the methods of the Filter interface to access the request and response objects and log  information. To set the log level for logging to the console, add the following configuration to your application.properties file.

logging.level.guru.springframework=DEBUG

On running the application, the container invokes the init() method. However, the container is yet to invoke thedoFilter() method.

Output of init method
Open a browser and access http://localhost:8080/meme. This invokes the doFilter() method.
Output of doFilter method

Finally, stop the application. This invokes the destroy() method.

output of destroy method

Filter Use Cases in Spring

The Spring Framework provides the GenericFilterBean class to configure filters in Spring Web applications. This class is a Spring specific base implementation of the Filter interface.  Let us look how to use GenericFilterBean to perform some common operations in filters.

Verifying Authentication Tokens

JSON Web Tokens (JWT) is one of the common authentication mechanism in Spring Boot REST services. In this type of authentication, client sends a JWT token to access a service. If you are working with microservices, instead of validating the token in each service, you can offload it to a filter.  Such filter can intercept the request and validate the token before passing the request to a service for processing.

The following code shows an example of such filter.

package guru.springframework.springfilter.filter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.filter.GenericFilterBean;

import java.io.IOException;

import io.jsonwebtoken.*;

public class JwtFilter extends GenericFilterBean {

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

        final HttpServletRequest request = (HttpServletRequest) req;
        final HttpServletResponse response = (HttpServletResponse) res;
        final String authHeader = request.getHeader("authorization");

        if ("OPTIONS".equals(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
            filterChain.doFilter(req, res);
        } else {
            if (authHeader == null || !authHeader.startsWith("Bearer ")) {
                throw new ServletException("Missing or invalid Authorization header");
            }

            final String token = authHeader.substring(7);
            final Claims claims = Jwts.parser()
                    .setSigningKey("secretkey")
                    .parseClaimsJws(token)
                    .getBody();

            request.setAttribute("claims", claims);
            filterChain.doFilter(req, res);

        }

    }
}

Logging Request Processing Time

You can use filters to log request processing time.

The following code shows an example of such a filter.

package guru.springframework.springfilter.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@Component
@Slf4j
public class RequestProcessingTimeFilter extends GenericFilterBean {
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain
            filterChain)throws IOException, ServletException {
                   long time = System.currentTimeMillis();
            try {
                filterChain.doFilter(req, res);
            } finally {
                time = System.currentTimeMillis() - time;
                log.debug("Request was processed in: {}: {} ms ", ((HttpServletRequest) req).getRequestURI(),  time);
            }
        }

      }

On running the application and sending a request, you can see the request processing time in milliseconds on the console.

request processing time filter

Filter Ordering in Filter Chain

I have shown configuring multiple filters in a Spring Web application. These filters can together form a filter chain in an application. A request goes through the chain of filters and reach the controller unless a filter throws some exception to stop the request flow.

When you have multiple filters forming a filter chain, you can set the invocation order of the filters. There are two approaches.

If you are using the @Component annotation in the filter class, you can set the ordering using the @Order annotation, like this.

@Component 
@Slf4j 
@Order(0)
public class MemeFilter implements Filter {
....
@Order(0)
}

@Component 
@Slf4j 
@Order(1)
public class JwtFilter implements Filter {
....
}

@Component 
@Slf4j 
@Order(2)
public class RequestProcessingTimeFilter implements Filter {
....
}

The preceding configuration will set the filter chain, like this.

filter chain ordering

 

The second approach is through Java configuration. In this approach you would have filter beans ordered and defined like this.

package guru.springframework.springfilter.config;


import guru.springframework.springfilter.filter.MemeFilter;
import guru.springframework.springfilter.filter.RequestProcessingTimeFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FilterBeanConfig {

    @Bean
    public FilterRegistrationBean requestMemeFilter() {
        MemeFilter memeFilter=new MemeFilter();
        final FilterRegistrationBean reg = new FilterRegistrationBean(memeFilter);
        reg.addUrlPatterns("/*");
        reg.setOrder(1); //defines filter execution order
        return reg;
    }

    @Bean
    public FilterRegistrationBean requestRequestProcessingTimeFilter() {
        RequestProcessingTimeFilter requestProcessingTimeFilter =new RequestProcessingTimeFilter();
        final FilterRegistrationBean reg = new FilterRegistrationBean(requestProcessingTimeFilter);
        reg.addUrlPatterns("/*");
        reg.setOrder(2); //defines filter execution order
        return reg;
    }


}

Summary

Developers often confuse between filters and Springs handler interceptor as both performs similar functions.

Handler interceptor is basically similar to a Servlet filter, but in contrast to the latter it just allows custom pre-processing with the option of prohibiting the execution of the handler itself. Handler interceptor also allows custom post-processing. Filters are more powerful, for example they allow for exchanging the request and response objects that are handed down the chain. Note that a filter gets configured in web.xml, and handler interceptor in the application context.

As a basic guideline, fine-grained handler-related pre-processing tasks are candidates for handler interceptors, especially factored-out common handler code and authorization checks. On the other hand, a filter is well-suited for request content and view content handling, like multipart forms and GZIP compression. This typically shows when one needs to map the filter to certain content types (e.g. images), or to all requests.

 

You can find the source code of this post here on Github.

For in-depth knowledge on filters, you can check my Udemy Best Seller Course Spring Framework 5: Beginner to Guru

About SFG Contributor

Staff writer account for Spring Framework Guru

    You May Also Like

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    This site uses Akismet to reduce spam. Learn how your comment data is processed.