Filter, Interceptor or AOP in Spring Boot – How to Choose the Right One

Spring Boot offers three mechanisms—Filter, Interceptor, and AOP—to intercept requests, each with distinct execution order, capabilities, and suitable scenarios; this article explains their differences, shows code examples, provides a comparison table, decision tree, and real‑world use cases to guide proper selection.

CodeNotes
CodeNotes
CodeNotes
Filter, Interceptor or AOP in Spring Boot – How to Choose the Right One

0. Execution Order

Client → Servlet container (Tomcat) → Filter chain → DispatcherServlet → Interceptor chain → AOP proxy (if pointcut matches) → Controller method → AOP proxy (after) → Interceptor chain (return) → Filter chain (return) → Servlet container → Client.

Filter is the outermost layer, closest to the client. AOP weaves before and after the target method.

1. Filter

Implements the Servlet specification and does not depend on Spring. It runs before the DispatcherServlet and after the response returns.

@Component
public class LoggingFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        long start = System.currentTimeMillis();
        System.out.println("Filter start: " + req.getRequestURI());
        chain.doFilter(request, response);
        long duration = System.currentTimeMillis() - start;
        System.out.println("Filter end: " + req.getRequestURI() + ", cost: " + duration + "ms");
    }
}

Can access HttpServletRequest and HttpServletResponse.

Cannot obtain Controller method information, parameters, or return values.

Applies to static resources as well.

Typical scenarios: character encoding conversion (e.g., CharacterEncodingFilter), CORS handling, request/response logging without business details, XSS protection, response compression.

2. Interceptor

Part of Spring MVC; runs after the request reaches the Controller and before the response leaves it.

@Component
public class LoggingInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        System.out.println("Interceptor preHandle: " + request.getRequestURI());
        return true; // continue processing
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
                           Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("Interceptor postHandle: Controller executed, before view rendering");
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                                Object handler, Exception ex) throws Exception {
        System.out.println("Interceptor afterCompletion: view rendered, before response");
    }
}

Registration example:

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private LoggingInterceptor loggingInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loggingInterceptor)
                .addPathPatterns("/api/**")
                .excludePathPatterns("/api/login");
    }
}

Can access request/response and also the Controller method via the handler argument.

In preHandle only method signature is available; parameters are not yet bound. postHandle can access ModelAndView (null for REST controllers).

Cannot access local variables inside the method.

Typical scenarios: login authentication, permission checks, API logging (request parameters and response), rate limiting, parameter preprocessing (e.g., pagination).

3. AOP

Core Spring feature that weaves before and after the target method execution, including exception handling.

@Aspect
@Component
public class LoggingAspect {
    private static final Logger log = LoggerFactory.getLogger(LoggingAspect.class);
    @Pointcut("execution(* com.example.service.*.*(..))")
    public void serviceMethod() {}
    @Around("serviceMethod()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        log.info("AOP Around start: {}.{}, args: {}", joinPoint.getTarget().getClass().getSimpleName(), methodName, args);
        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        long duration = System.currentTimeMillis() - start;
        log.info("AOP Around end: {}.{}, return: {}, cost: {}ms", joinPoint.getTarget().getClass().getSimpleName(), methodName, result, duration);
        return result;
    }
    @AfterThrowing(pointcut = "serviceMethod()", throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint, Exception ex) {
        log.error("AOP exception: {}.{}, ex: {}", joinPoint.getTarget().getClass().getSimpleName(), joinPoint.getSignature().getName(), ex.getMessage());
    }
}

Can obtain method parameters, return values, method signature, and exceptions.

Can modify parameters and return values.

Cannot directly access local variables inside the method.

Does not depend on HttpServletRequest, thus works for non‑Web scenarios.

Typical scenarios: transaction management ( @Transactional), method execution time monitoring, logging that needs parameters and return values, caching ( @Cacheable), parameter validation, data desensitization, retry and fallback mechanisms.

4. Comparison

Layer : Filter – Servlet specification; Interceptor – Spring MVC; AOP – Spring core.

Execution timing : Filter – before/after DispatcherServlet; Interceptor – before/after Controller; AOP – before/after method execution.

Access to request/response : Filter – full; Interceptor – full; AOP – requires explicit injection.

Access to Controller method : Filter – none; Interceptor – yes (via handler); AOP – only if pointcut targets the Controller.

Access to method parameters : Filter – none; Interceptor – none (parameters not bound); AOP – yes.

Modify return value : Filter – no; Interceptor – only ModelAndView in MVC; AOP – yes.

Capture business exception : Filter – only outward exceptions; Interceptor – only in afterCompletion; AOP – yes.

Applicable scope : Filter – general Web layer; Interceptor – Web‑layer interception; AOP – business‑layer enhancement; AOP also works for non‑Web methods.

5. Decision Tree

Does the logic depend on Web (request/response)?
├─ No → Use AOP (transactions, caching, logging, monitoring)
└─ Yes → Need Controller info?
    ├─ No → Use Filter (encoding, CORS, XSS)
    └─ Yes → Need to modify return value or capture business exception?
        ├─ No → Use Interceptor (auth, permission, rate‑limit)
        └─ Yes → Use AOP (weave at Controller layer)

6. Real‑World Scenarios

Scenario 1 – Full‑link Log Tracing (Filter + MDC)

@Component
public class TraceFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        String traceId = UUID.randomUUID().toString();
        MDC.put("traceId", traceId);
        try {
            chain.doFilter(request, response);
        } finally {
            MDC.clear();
        }
    }
}

Filter is chosen because the trace ID must be generated at the request entry point and no Controller information is required.

Scenario 2 – Login Authentication (Interceptor)

@Component
public class AuthInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String token = request.getHeader("Authorization");
        if (token == null || !authService.validate(token)) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }
        return true;
    }
}

Interceptor is needed to read request headers and to know which Controller method is being invoked.

Scenario 3 – Method Execution Time Monitoring (AOP)

@Aspect
@Component
public class PerformanceAspect {
    @Around("@annotation(com.example.annotation.Monitor)")
    public Object monitor(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        try {
            return joinPoint.proceed();
        } finally {
            long duration = System.currentTimeMillis() - start;
            log.info("{} took {}ms", joinPoint.getSignature(), duration);
        }
    }
}

AOP is chosen because precise method‑level timing and access to parameters and return values are required.

7. Summary

Filter : Outermost layer, independent of Spring, best for generic Web concerns such as encoding, CORS, XSS, and request‑wide logging.

Interceptor : Middle layer within Spring MVC, ideal for Web‑level interception that needs Controller metadata (authentication, permission, rate limiting).

AOP : Innermost, Spring core, perfect for business‑level enhancements that require method parameters, return values, or exception handling (transactions, caching, detailed logging, monitoring).

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.

AOPSpring BootInterceptorFilterRequest Handling
CodeNotes
Written by

CodeNotes

Discuss code and AI, and document daily life and personal growth.

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.