Ways to add Servlet Filters in Spring Boot
In this post, We will take a look at ways to add servlet filters to your spring boot application. Servlet filters help a web application in many ways. They intercept requests and responses to provide different behaviors based on requests. Some of them are,
- Authentication and Authorization filters that help deal with security.
- Logging Filters that provide tracing information for loggers.
- Filters that deal with request validation.
- Localization – Targeting the request and response to a particular locale.
There are four ways in which you can add servlet filters to a spring boot application. Let’s go through each one of them with some examples.
Using OncePerRequestFilter bean
The good thing about spring boot is that it always provides you with ways to override the default behavior. In this case, you can create an OncePerRequestFilter bean to supply your filter logic for a spring boot application.
@Configuration
public class ServletConfiguration {
@Bean
OncePerRequestFilter mdcFilter() {
return new OncePerRequestFilter() {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
MDC.put("x-debug-token", UUID.randomUUID().toString());
filterChain.doFilter(request, response);
MDC.remove("x-debug-token");
}
};
}
}
Code language: PHP (php)
For example, the above mdcFilter places a debug token in the logging context(MDC). We can use this token to trace out all the log entries that occurred for a specific request.
To see the trace token in the log, you just need to add %mdc to your logger pattern. In my case, I’m changing the log pattern through the following configuration properties.
logging.pattern.console=%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} {%mdc}: %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}
Code language: Properties (properties)
If we do all of this right and have an API to call, then you would see logs like this.
The above approach comes to help if you are writing a quick filter like in the example.
Using @Component to add Filter classes to Spring Boot
The second approach is to make all your filters as @Component. By default, if spring boot finds a component of type Filter, then it will add it to the servlet context.
@Component
public class FilterOne implements Filter {
private static final Logger logger = LoggerFactory.getLogger(FilterOne.class);
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
logger.info("Executing FilterOne");
filterChain.doFilter(servletRequest, servletResponse);
}
}
Code language: JavaScript (javascript)
If you have more than one filter and you want to make sure they execute in a specific order, then use bean order.
@Component
@Order(1)
public class FilterOne implements Filter {
}
@Component
@Order(2)
public class FilterTwo implements Filter {
}
Code language: PHP (php)
You could also use the @Order(Ordered.HIGHEST_PRECEDENCE) to indicate that the filter should take the highest order of precedence in the spring boot filter chain.
While the first and second approaches seem easy and simple, You cannot assign these filters to a particular URL pattern. So let’s explore the other options.
Using Filter registration in Spring Boot
This approach is optimal when you already have a filter class(possibly from a library) and you just want to add them to your application. The usual situation would be for registering a security filter/ Locale support etc.
As the name suggests, A FilterRegistrationBean lets you register an already existing filter class into the servlet context. The following snippet can explain this better.
@Bean
FilterRegistrationBean<SomeThirdPartyFilter> filterFilterRegistrationBean() {
FilterRegistrationBean<SomeThirdPartyFilter> mySampleFilterFilterRegistrationBean = new FilterRegistrationBean<>();
mySampleFilterFilterRegistrationBean.addUrlPatterns("/api/*");
mySampleFilterFilterRegistrationBean.setFilter(new SomeThirdPartyFilter());
return mySampleFilterFilterRegistrationBean;
}
Code language: JavaScript (javascript)
When spring boot finds this filter registration bean, it simply adds it to the servlet context. Here we also specified a URL pattern the filter should be applied for.
Using ServletComponentScan annotation
If you do not plan to register each filter bean on your own, Then you can define the @ServletComponentScan
annotation on your spring boot application class. This annotation looks through all packages to find any Filter bean and register them for you.
For example, you can define a web filter like below.
@WebFilter(urlPatterns = "/*")
public class SomeFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(SomeFilter.class);
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
logger.info("Executing SomeFilter");
filterChain.doFilter(servletRequest, servletResponse);
}
}
Code language: JavaScript (javascript)
Note that the @WebFilter is important as the scan happens based on this annotation. If you do not provide this annotation, then the scan won’t include this filter. Next, you need to add the @ServletComponentScan
annotation to one of your configuration or application classes.
@ServletComponentScan
@SpringBootApplication
public class SpringBootServletFiltersApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootServletFiltersApplication.class, args);
}
}
Code language: PHP (php)
Summary
We learned all four ways in which we can add a filter in a spring boot web application. They are,
- Adding filters through OncePerRequestFilter bean
- Using @Component to make Spring Boot detect filter classes
- Registering Filters using FilterRegistrationBean for a specific path
- Using the @WebFilter and @ServletComponentScan annotations