In a Spring Boot application, managing HTTP requests and responses is critical for implementing cross-cutting concerns such as logging, security, and authentication. Interceptors and Filters provide two key mechanisms for this purpose. Additionally, you might need to specify the order in which these interceptors and filters are executed to ensure the correct flow of operations.
In this post, we’ll walk through how to create both a custom Interceptor and a custom Filter in Spring Boot, and how to define the order in which they should be executed.
What is an Interceptor?
An Interceptor operates at the Spring MVC level, allowing you to:
- Pre-process requests before they are handled by a controller.
- Post-process responses after the controller has processed them.
- Execute code after the request has been completed.
What is a Filter?
A Filter operates at a lower level, within the servlet layer, and allows for global manipulation of requests and responses. Filters can be used to:
- Modify incoming requests before they reach a servlet.
- Modify outgoing responses after they leave a servlet.
Creating a Custom Interceptor in Spring Boot
Let’s start by creating a simple Interceptor that logs messages during the request lifecycle.
1. Implementing the Interceptor
To create an interceptor, implement the HandlerInterceptor
interface. This interface has three important methods:
preHandle
: Executed before the request is handled by the controller.postHandle
: Executed after the controller has processed the request but before the view is rendered.afterCompletion
: Executed after the complete request cycle is done.
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class CustomInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("Pre Handle method is Calling");
return true; // Continue request processing
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
org.springframework.web.servlet.ModelAndView modelAndView) throws Exception {
System.out.println("Post Handle method is Calling");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception)
throws Exception {
System.out.println("Request and Response is completed");
}
}
2. Registering the Interceptor
To activate your interceptor, you need to register it by overriding the addInterceptors
method in a configuration class.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private CustomInterceptor customInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(customInterceptor).addPathPatterns("/**"); // Intercepts all paths
}
}
Creating a Custom Filter in Spring Boot
Now, let’s create a Filter. Filters operate at the servlet level and are used for tasks like logging, session validation, or security enforcement.
1. Implementing the Filter
To create a custom filter, implement the Filter
interface. The doFilter
method is where you define what the filter does.
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(urlPatterns = "/*") // Applies the filter to all URL patterns
public class CustomFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// Initialization logic if needed
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("Request is being filtered");
chain.doFilter(request, response); // Continue the filter chain
}
@Override
public void destroy() {
// Cleanup logic if needed
}
}
2. Registering the Filter
To register the filter, you can either use @WebFilter
(as shown above) or FilterRegistrationBean
in a configuration class.
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<CustomFilter> loggingFilter() {
FilterRegistrationBean<CustomFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new CustomFilter());
registrationBean.addUrlPatterns("/api/*"); // Apply to specific URL patterns
return registrationBean;
}
}
How to Control the Execution Order of Filters and Interceptors
When you have multiple interceptors or filters, you may need to specify the order in which they are executed. Here’s how you can achieve that:
Ordering Filters
You can set the order of filters using the @Order
annotation or FilterRegistrationBean#setOrder()
.
Using @Order
:
import org.springframework.core.annotation.Order;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
@Order(1) // This filter will be executed first
@WebFilter(urlPatterns = "/*")
public class FirstFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("First filter before");
chain.doFilter(request, response);
System.out.println("First filter after");
}
}
Using FilterRegistrationBean
:
@Bean
public FilterRegistrationBean<FirstFilter> firstFilter() {
FilterRegistrationBean<FirstFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new FirstFilter());
registrationBean.addUrlPatterns("/*");
registrationBean.setOrder(1); // Order of execution
return registrationBean;
}
Ordering Interceptors
Interceptors are executed in the order they are registered in the InterceptorRegistry
.
Example of Two Interceptors:
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class FirstInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("First Interceptor before");
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("First Interceptor after");
}
}
@Component
public class SecondInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("Second Interceptor before");
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("Second Interceptor after");
}
}
Registering Interceptors in Order:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private FirstInterceptor firstInterceptor;
@Autowired
private SecondInterceptor secondInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(firstInterceptor).addPathPatterns("/**"); // This runs first
registry.addInterceptor(secondInterceptor).addPathPatterns("/**"); // This runs second
}
}
Conclusion
- Filters and Interceptors in Spring Boot help you intercept and modify requests and responses at different levels.
- You can easily control their execution order using the
@Order
annotation,FilterRegistrationBean#setOrder()
for filters, and registration order for interceptors. - Interceptors are ideal for pre-processing and post-processing controller requests, while filters are used for more general request/response manipulation.