Spring interceptor process and sequence of multiple interceptors

Keywords: Spring

        Interceptor is a component in Spring MVC. It can do some operations before entering the request method, or after requesting the method and rendering the view.

Definition of interceptor

        The interceptor of spring MVC only needs to implement the HandlerInterceptor interface and configure it. The HandlerInterceptor interface is defined as follows:  

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 modelAndView) throws Exception {
    }

    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    }
}

        There are three methods in HandlerInterceptor. The meaning of each method is as follows:

preHandler: execute before entering the request method;

postHandler: execute after the request method is executed;

After completion: executed after the view is rendered.

Execution process of interceptor

         In the preHandle method, its return value is of boolean type. Its return value affects the request method, as well as the execution of postHandle and afterCompletion. The details are as follows.

        In other words, if false is returned in the preHandle, the subsequent processes will not be executed, which may also be the origin of the interceptor's name.

Test interceptor

        Write a simple interceptor with the following code:  

@Slf4j
public class TestInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("preHandler");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("postHandler");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("afterCompletion");
    }
}

        A listener class of TestInterceptor is created, which implements all interfaces of HandlerInterceptor. After writing TestInterceptor, you also need to register. The code is as follows:

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(testInterceptor());
    }

         Then write a simple request method. The code is as follows:

@GetMapping("test")
public String test()
{
    return "test";
}

        To start our project and access it. The console output is as follows:

2021-05-05 16:02:08.110  INFO 88509 --- [nio-8081-exec-6] com.example.demo.TestInterceptor         : preHandler
2021-05-05 16:02:08.111  INFO 88509 --- [nio-8081-exec-6] com.example.demo.TestInterceptor         : postHandler
2021-05-05 16:02:08.111  INFO 88509 --- [nio-8081-exec-6] com.example.demo.TestInterceptor         : afterCompletion

Execution sequence of multiple interceptors

         Let's write several of the same listeners, namely TestInterceptor, TestInterceptor2 and TestInterceptor3. Then we register, and the registration code is as follows:

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(testInterceptor());
    registry.addInterceptor(testInterceptor2());
    registry.addInterceptor(testInterceptor3());
}

        Request our method, and the output is as follows:

2021-05-05 16:09:57.735  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor         : preHandler
2021-05-05 16:09:57.736  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor2        : preHandler2
2021-05-05 16:09:57.736  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor3        : preHandler3
2021-05-05 16:09:57.755  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor3        : postHandler3
2021-05-05 16:09:57.755  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor2        : postHandler2
2021-05-05 16:09:57.755  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor         : postHandler
2021-05-05 16:09:57.755  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor3        : afterCompletion3
2021-05-05 16:09:57.755  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor2        : afterCompletion2
2021-05-05 16:09:57.755  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor         : afterCompletion

        Note the order of output. The preHandle method is executed in the registration order, while the postHandle and afterCompletion are in the opposite order.

Let preHandle intercept

        Let's make the return value of the preHandle of TestInterceptor2 false, and then look at the output.

2021-05-05 16:14:00.997  INFO 88582 --- [nio-8081-exec-1] com.example.demo.TestInterceptor         : preHandler
2021-05-05 16:14:00.998  INFO 88582 --- [nio-8081-exec-1] com.example.demo.TestInterceptor2        : preHandler2
2021-05-05 16:14:00.998  INFO 88582 --- [nio-8081-exec-1] com.example.demo.TestInterceptor         : afterCompletion

         You can see that after the return value of the preHandle of TestInterceptor2 is false, it is equivalent to that the subsequent process of the preHandle of TestInterceptor2 will not continue.

        Let's adjust the registration order. The code is as follows:

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(testInterceptor2());
    registry.addInterceptor(testInterceptor());
    registry.addInterceptor(testInterceptor3());
}

        The output after modifying the sequence is as follows:

2021-05-05 16:17:23.956  INFO 88589 --- [nio-8081-exec-1] com.example.demo.TestInterceptor2        : preHandler2

        You can see that the processes behind it have been intercepted and have no chance to execute.

summary

        Interceptors are saved using a List. We can add multiple interceptors to the project to complete different functions, such as Token verification, permission acquisition, etc. We can put it into different interceptors for related operations.

Posted by zahadum on Sun, 28 Nov 2021 07:37:56 -0800