Backend Development 8 min read

Master Spring Boot Interceptors: From Basics to Advanced Techniques

This article explains what Spring MVC interceptors are, when to use them, provides a simple implementation and registration example, and then dives into advanced patterns such as MappedInterceptor, global interceptors, and asynchronous interceptors with complete code snippets and usage guidance.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Master Spring Boot Interceptors: From Basics to Advanced Techniques

1. Introduction

What is an interceptor? An interceptor is part of Spring MVC that works inside the Spring framework and allows you to modify requests and responses for specific controllers.

When should you use an interceptor? Use it for Spring‑specific logic such as:

Authentication and authorization: verify user credentials and permissions.

Recording execution time: measure and track how long a controller takes to handle a request.

Modifying model/view: adjust the model or view before sending the response.

Adding common attributes: include shared data (e.g., user details) in all responses.

Simple interceptor implementation

<code>public class DemoInterceptor implements HandlerInterceptor {
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    System.err.println("preHandle...");
    return true;
  }

  @Override
  public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    System.err.println("postHandle...");
  }

  @Override
  public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    System.err.println("afterCompletion...");
  }
}</code>

Register the interceptor:

<code>@Component
public class DemoConfig implements WebMvcConfigurer {
  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new DemoInterceptor())
            .addPathPatterns("/api/*");
  }
}</code>

When a request matches /api/* , the callbacks are executed, producing output such as:

<code>preHandle...
api query...
postHandle...
afterCompletion...</code>

2. Advanced Cases

2.1 MappedInterceptor

Spring provides MappedInterceptor as a wrapper that matches URL patterns and automatically picks beans from the container.

<code>public class AuthInterceptor implements HandlerInterceptor {
  private static final Logger logger = LoggerFactory.getLogger(AuthInterceptor.class);
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    logger.info("权限验证...");
    return true;
  }
}</code>
<code>@Bean
MappedInterceptor authInterceptor(@Value("${pack.auth.patterns}") String[] includePatterns) {
  return new MappedInterceptor(includePatterns, new AuthInterceptor());
}</code>

2.2 Global Interceptor

By extending RequestMappingHandlerMapping you can add interceptors to all requests.

<code>@Component
public class PackHandlerMapping extends RequestMappingHandlerMapping {
  private final List<HandlerInterceptor> interceptors;
  public PackHandlerMapping(List<HandlerInterceptor> interceptors) {
    this.interceptors = interceptors;
  }
  @Override
  protected void extendInterceptors(List<Object> interceptors) {
    List<HandlerInterceptor> ret = this.interceptors.stream()
        .filter(i -> !(i instanceof MappedInterceptor))
        .collect(Collectors.toList());
    interceptors.addAll(ret);
  }
  @Override
  public int getOrder() {
    return Ordered.HIGHEST_PRECEDENCE;
  }
}</code>

2.3 Asynchronous Interceptor

Spring MVC provides AsyncHandlerInterceptor with an extra method afterConcurrentHandlingStarted for async request processing.

<code>@Component
public class AsyncLogInterceptor implements AsyncWebRequestInterceptor {
  public void preHandle(WebRequest request) {
    System.err.printf("AsyncWebRequestInterceptor >>> %s, %s, 开始处理%n", System.currentTimeMillis(), Thread.currentThread().getName());
  }
  public void postHandle(WebRequest request, ModelMap model) {
    System.err.printf("AsyncWebRequestInterceptor >>> %s, postHandle%n", Thread.currentThread().getName());
  }
  public void afterCompletion(WebRequest request, Exception ex) {
    System.err.printf("AsyncWebRequestInterceptor >>> %s afterCompletion%n", Thread.currentThread().getName());
  }
  public void afterConcurrentHandlingStarted(WebRequest request) {
    System.err.printf("AsyncWebRequestInterceptor >>> %s, %s, 异步处理%n", System.currentTimeMillis(), Thread.currentThread().getName());
  }
}</code>
<code>@Component
public class WebInterceptorConfig implements WebMvcConfigurer {
  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addWebRequestInterceptor(new AsyncLogInterceptor())
            .addPathPatterns("/admin/**");
  }
}</code>

Define a controller to test async handling:

<code>@GetMapping("/async")
public Callable<String> async() {
  return new Callable<String>() {
    public String call() throws Exception {
      System.err.printf("%s, %s - 执行任务%n", System.currentTimeMillis(), Thread.currentThread().getName());
      TimeUnit.SECONDS.sleep(3);
      return "异步数据";
    }
  };
}</code>

Result is shown in the following image:

BackendJavaSpring BootInterceptorTutorialAsyncSpring MVC
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

login 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.