Master Java Web Filters and Interceptors: Tutorials, Implementation Details, and Key Differences

This article explains the purpose, lifecycle, and configuration of Java Servlet Filters and Spring MVC Interceptors, compares their execution order with Spring AOP aspects, provides complete code examples for each component, and offers guidance on choosing the right mechanism for specific business requirements.

Shepherd Advanced Notes
Shepherd Advanced Notes
Shepherd Advanced Notes
Master Java Web Filters and Interceptors: Tutorials, Implementation Details, and Key Differences

1. Overview

Filters and Interceptors are two common components in Java Web development used for pre‑processing and post‑processing of requests and responses. Although they share similar goals such as logging, authentication, and character‑encoding handling, they differ in scope, lifecycle management, and integration points.

2. Filters

2.1 Usage Example

public interface Filter {
    default void init(FilterConfig filterConfig) throws ServletException {}
    void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException;
    default void destroy() {}
}

@Component
@Slf4j
@WebFilter(urlPatterns = "/*")
@Order(2)
public class AFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("Filter A: init executed");
    }
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        log.info("Filter A: doFilter executed");
        chain.doFilter(req, res);
    }
    @Override
    public void destroy() {
        log.info("Filter A: destroy executed");
    }
}

@Component
@Slf4j
@WebFilter(urlPatterns = "/*")
@Order(1)
public class BFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("Filter B: init executed");
    }
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        log.info("Filter B: doFilter executed");
        chain.doFilter(req, res);
    }
    @Override
    public void destroy() {
        log.info("Filter B: destroy executed");
    }
}

When the application starts, the container calls init() once for each filter; on each request, doFilter() is invoked; on shutdown, destroy() runs.

2.2 Registration via Spring Boot

@Configuration
public class MyConfig {
    @Resource
    private AFilter aFilter;
    @Resource
    private BFilter bFilter;

    @Bean
    public FilterRegistrationBean<Filter> buildBFilter() {
        FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>();
        bean.setFilter(bFilter);
        bean.addUrlPatterns("/*");
        bean.setName("BFilter");
        bean.setOrder(2);
        return bean;
    }

    @Bean
    public FilterRegistrationBean<Filter> buildAFilter() {
        FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>();
        bean.setFilter(aFilter);
        bean.addUrlPatterns("/*");
        bean.setName("AFilter");
        bean.setOrder(1);
        return bean;
    }
}

Using @Order on the filter class or on the FilterRegistrationBean determines execution order; without explicit order, beans are invoked in the order they are discovered by Spring.

3. Interceptors

3.1 Usage Example

public interface HandlerInterceptor {
    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception { return true; }
    default void postHandle(HttpServletRequest request, HttpServletResponse response,
                           Object handler, @Nullable ModelAndView mv) throws Exception {}
    default void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                                 Object handler, @Nullable Exception ex) throws Exception {}
}

@Component
@Slf4j
public class AInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        log.info("AInterceptor preHandle executed");
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
                           Object handler, ModelAndView mv) {
        log.info("AInterceptor postHandle executed");
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                                Object handler, Exception ex) {
        log.info("AInterceptor afterCompletion executed");
    }
}

@Component
@Slf4j
public class BInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        log.info("BInterceptor preHandle executed");
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
                           Object handler, ModelAndView mv) {
        log.info("BInterceptor postHandle executed");
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                                Object handler, Exception ex) {
        log.info("BInterceptor afterCompletion executed");
    }
}

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Resource
    private AInterceptor aInterceptor;
    @Resource
    private BInterceptor bInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(bInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/user/**")
                .order(2);
        registry.addInterceptor(aInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/user/**")
                .order(1);
    }
}

Interceptors run preHandle before the controller, postHandle after the controller but before view rendering, and afterCompletion after the view is rendered.

4. Execution Order with Aspect

@Aspect
@Component
@Slf4j
public class LogAspect {
    @Around("execution(* com.shepherd..controller..*(..))")
    public Object timeAround(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("Executing @Aspect method");
        return joinPoint.proceed();
    }
}

Log output shows the real execution sequence:

Filter A -> Filter B -> Interceptor A preHandle -> Interceptor B preHandle ->
@Aspect timeAround -> Controller method -> Interceptor B postHandle ->
Interceptor A postHandle -> Interceptor B afterCompletion -> Interceptor A afterCompletion

Conclusion: Filter → Interceptor → @Aspect → Controller .

5. Internal Implementation Details

Filters are chained by ApplicationFilterChain. Each doFilter() call forwards to the next filter via filterChain.doFilter(). The chain is built in ApplicationFilterFactory#createFilterChain(), which matches URL patterns and dispatcher types, then adds matching FilterConfig objects.

public final class ApplicationFilterChain implements FilterChain {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response) {
        // iterate over filters array
        internalDoFilter(request, response);
    }
    private void internalDoFilter(ServletRequest request, ServletResponse response) {
        if (pos < n) {
            FilterConfig config = filters[pos++];
            Filter filter = config.getFilter();
            filter.doFilter(request, response, this);
        }
    }
}

Spring MVC builds a HandlerExecutionChain that holds the target handler and the list of interceptors. The doDispatch method of DispatcherServlet invokes: applyPreHandle (forward iteration of interceptors)

handler execution applyPostHandle (reverse iteration) triggerAfterCompletion (reverse iteration)

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) {
    for (int i = 0; i < interceptorList.size(); i++) {
        HandlerInterceptor interceptor = interceptorList.get(i);
        if (!interceptor.preHandle(request, response, handler)) {
            triggerAfterCompletion(request, response, null);
            return false;
        }
    }
    return true;
}

void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) {
    for (int i = interceptorList.size() - 1; i >= 0; i--) {
        HandlerInterceptor interceptor = interceptorList.get(i);
        interceptor.postHandle(request, response, handler, mv);
    }
}

void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex) {
    for (int i = interceptorIndex; i >= 0; i--) {
        HandlerInterceptor interceptor = interceptorList.get(i);
        try { interceptor.afterCompletion(request, response, handler, ex); }
        catch (Throwable t) { logger.error("HandlerInterceptor.afterCompletion threw exception", t); }
    }
}

6. Comparison and Selection Guidance

• Filter : operates at the servlet container level, can modify raw HTTP request/response, suitable for tasks that must run before Spring MVC (e.g., character encoding, global authentication, trace‑ID injection).

• Interceptor : works within Spring MVC, has access to handler method arguments and ModelAndView, ideal for controller‑level concerns such as permission checks or response wrapping.

• @Aspect : AOP mechanism that can target any join point, useful for cross‑cutting concerns like transaction management, performance monitoring, or logging that span multiple layers.

Choose the component that matches the required execution point and the data you need to manipulate.

7. Summary

Filters, Interceptors, and Aspects all embody AOP concepts in Java Web applications. They differ in scope, lifecycle, and execution order. Understanding their internal chaining mechanisms and ordering rules enables developers to select the most appropriate tool for a given requirement, avoiding redundant implementations and ensuring predictable request processing.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavawebAOPinterceptorfilteraspectspring-boot
Shepherd Advanced Notes
Written by

Shepherd Advanced Notes

Dedicated to sharing advanced Java technical insights, daily work snippets, and the power of persistent effort.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.