1. Overview

In this tutorial, we'll look at how we can create web filters using Spring MVC.

2. Using a Spring Bean

Spring MVC will register any bean that extends HttpFilter as a web filter.  When we create a filter this way, the default URL pattern becomes /*.

@Slf4j
@Component
public class DateLoggingFilter extends HttpFilter {

    @Override
    protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
      throws IOException, ServletException {
        log.info("New request at date: {}", new Date());

        chain.doFilter(request, response);
    }
}

Here, we're declaring DateLoggingFilter as a Spring bean. As a result, Spring MVC will register this bean as a web filter.

2.1. Ordering

Generally, the ordering of filters doesn't make a difference. But if the processing of one filter depends on another, we must modify their order in the filter chain. There are two ways to achieve this.

Firstly, we can order our filters using the @Order annotation:

@Component
@Order(Ordered.LOWEST_PRECEDENCE - 1)
public class DateLoggingFilter extends HttpFilter {

    // Implementation details...
}

Here, we have the previously defined DateLoggingFilter and we're setting its order as Ordered.LOWEST_PRECEDENCE - 1 in the @Order annotation

Alternatively, we can implement the Ordered interface:

@Slf4j
@Component
public class TimeLoggingFilter extends HttpFilter implements Ordered {

    @Override
    protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
      throws IOException, ServletException {
        log.info("New request at time: {}", new Time(System.currentTimeMillis()));

        chain.doFilter(request, response);
    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE - 99;
    }
}

Here, TimeLoggingFilter has the order of Ordered.LOWEST_PRECEDENCE - 99.

Now that we have two filters with different orders, we'll investigate their invocation order.

First of all, Ordered.LOWEST_PRECEDENCE holds the value of Integer.MAX_VALUE, and Ordered.HIGHEST_PRECEDENCE is Integer.MIN_VALUE. So the precedence increases when the order number decreases.

Additionally, the filters with the higher precedence will run earlier in the filter chain.

As a result, TimeLoggingFilter has higher precedence and will run before DateLoggingFilter.

3. Using FilterRegistrationBean

When we create a web filter using a Spring bean, it gets the default URL pattern and we don't have too much control on other registration properties. FilterRegistrationBean allows us to define different registration properties of a web filter.

@Configuration
public class FilterConfiguration {

    private final DateLoggingFilter dateLoggingFilter;

    @Autowired
    public FilterConfiguration(DateLoggingFilter dateLoggingFilter) {
        this.dateLoggingFilter = dateLoggingFilter;
    }

    @Bean
    public FilterRegistrationBean<DateLoggingFilter> dateLoggingFilterRegistration() {
        FilterRegistrationBean<DateLoggingFilter> filterRegistrationBean = new FilterRegistrationBean<>();
        filterRegistrationBean.setFilter(dateLoggingFilter);
        filterRegistrationBean.setUrlPatterns(Collections.singletonList("/*"));
        filterRegistrationBean.setDispatcherTypes(DispatcherType.REQUEST);
        filterRegistrationBean.setOrder(Ordered.LOWEST_PRECEDENCE - 1);
        return filterRegistrationBean;
    }
}

Here, we're using the DateLoggingFilter bean but we are defining the filter registration explicitly by a FilterRegistrationBean<DateLoggingFilter> bean. In addition to the URL pattern, we're also setting the dispatcher types and order of the filter.

4. Using @WebFilter and @ServletComponentScan

With the Servlet 3.0 specification, we can use the @WebFilter annotation among others. Spring MVC has special support for scanning classes annotated with these annotations.

We'll first create a filter using @WebFilter:

@Slf4j
@WebFilter(urlPatterns = "/*", dispatcherTypes = {DispatcherType.REQUEST})
public class MethodLoggingFilter extends HttpFilter {

    @Override
    protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
      throws IOException, ServletException {
        log.info("New request with {}", request.getMethod());

        chain.doFilter(request, response);
    }
}

Note that we're specifying the URL patterns and dispatcher types inside the annotation.

After creating the filter, we'll make Spring scan these classes using @ServletComponentScan:

@Configuration
@ServletComponentScan
public class FilterConfiguration {

    // Bean definitions 
}

When the web application starts up, our MethodLoggingFilter will be active in the filter chain.

5. Summary

In this tutorial, we've investigated how to create web filters using Spring MVC.

Firstly we created Spring beans extending HttpFilter class. Then we looked at how we can customize the registration process using FilterRegistrationBean. Lastly, we investigated @WebFilter coming from the Servlet 3.0 specification.

Check out the source code for all examples over on Github.