Original blog address: pjmike’s blog

preface

Although filters and interceptors were used in the actual development of the project before, I was still a little ignorant in understanding them, so this article will carefully analyze the difference and connection between the two.

The filter

The Filter, defined in the Servlet specification, is supported by the Servlet container. This interface is defined under the Javax. Servlet package and is mainly preprocessed in the client request (HttpServletRequest). And post-processing of the server response (HttpServletResponse). The interface code is as follows:

package javax.servlet;

import java.io.IOException;

public interface Filter {
    void init(FilterConfig var1) throws ServletException;

    void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException;

    void destroy(a);
}
Copy the code

Analyze the above three interface methods:

  • Init (FilterConfig): The initialization interface, called when a user-defined Filter is initialized, serves the same purpose as the init method of the Servlet.
  • doFilter(ServletRequest,ServletResponse,FilterChain)This method is called every time a user’s request comes in, and is called before the Servlet’s service method (if we are developing a Servlet project), and FilterChain represents the entire current request chain, through the callFilterChain.doFilterYou can pass the request on, and if you want to intercept the request, you don’t have to call filterchain-dofilter, and the request is returned,So Filter is a chain of responsibility design patternIn thespring securityI use a lot of filters. I have a chain of filters.
  • Destroy: This method is called when the Filter object is destroyed. Note that after the Web container calls this method, the container calls the doFilter method again.

User-defined Filter

The springBoot custom Filter class is as follows:

@Component
public class MyFilter implements Filter {
    private Logger logger = LoggerFactory.getLogger(MyFilter.class);
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        logger.info("filter init");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        logger.info("doFilter");
        // Preprocess request and response
        //TODO does business logic
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy(a) {
        logger.info("filter destroy"); }}Copy the code

FilterRegistrationBean way

The FilterRegistrationBean method is provided in SpringBoot, which provides the setOrder method to set sorting values for multiple filters. The code is as follows:

@Configuration
public class FilterConfig {
    /** * Configures a Filter registrar **@return* /
    @Bean
    public FilterRegistrationBean filterRegistrationBean1(a) {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        registrationBean.setFilter(filter1());
        registrationBean.setName("filter1");
        // Set the sequence
        registrationBean.setOrder(10);
        return registrationBean;
    }
    @Bean
    public FilterRegistrationBean filterRegistrationBean2(a) {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        registrationBean.setFilter(filter2());
        registrationBean.setName("filter2");
        // Set the sequence
        registrationBean.setOrder(3);
        return registrationBean;
    }
    @Bean
    public Filter filter1(a) {
        return new MyFilter();
    }

    @Bean
    public Filter filter2(a) {
        return newMyFilter2(); }}Copy the code

The interceptor

Interceptors are a Spring concept that acts like filters, intercepting user requests and processing them accordingly, allowing for more fine-grained control.

In SpringMVC, the DispatcherServlet captures each request, which can be processed by the interceptor before it reaches the corresponding Controller, where it is pre-processed before it finally reaches the Controller.

The interceptor interface is org. Springframework. Web. Servlet. HandlerInterceptor interface, the interface code is 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 {}}Copy the code

Interface method interpretation:

  • The preHandle method prehandles the request from the client. If the method returns true, it continues. If false, it interrupts the request and does not send it to the Controller
  • PostHandler method: after the request is processed, that is, after the Controller method call, but beforepreHandleMethod returns true. Specifically,postHandlerThe method will be called before the DispatcherServlet does the view return rendering, which means we can handle the Controller later in this methodModelAndViewObject to operate on
  • AfterCompletion method: This method is executed after the entire request is completed, of coursepreHandleMethod returns true. This method is generally used for resource cleanup

Custom interceptors

public class MyInterceptor implements HandlerInterceptor {
    private Logger logger = LoggerFactory.getLogger(MyInterceptor.class);
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        logger.info("preHandle....");
        return true;
    }

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

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

Register interceptors and configure interceptor rules

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(handlerInterceptor())
                // Configure an interception rule
                .addPathPatterns("/ * *");
    }
    @Bean
    public HandlerInterceptor handlerInterceptor(a) {
        return newMyInterceptor(); }}Copy the code

Multiple interceptors work together

In springMVC we can implement multiple interceptors and register them in sequence as follows:

   public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(handlerInterceptor())
                .addPathPatterns("/ * *");
        registry.addInterceptor(handlerInterceptor2())
                .addPathPatterns("/ * *");
    }
Copy the code

The order of interceptors also depends on the order in which they were registered, at least for the preHandle method, as shown in the following figure when two interceptors work together:

The image above is from MOOC

The background log also outputs the same execution order:

io-9999-exec-2] c.p.filter.interceptor.MyInterceptor : preHandle.... The 2018-09-13 12:13:31. 9736-292 the INFO [nio - 9999 - exec - 2] C.P.F ilter. Interceptor. MyInterceptor2: preHandle2... The 2018-09-13 12:13:31. 9736-388 the INFO [nio - 9999 - exec - 2] C.P.F ilter. Controller. HelloController: Username: pjmike, password: 123456 2018-09-13 12:13:31. 9736-418 the INFO [nio - 9999 - exec - 2] c.p.filter.interceptor.MyInterceptor2 : postHandle2... The 2018-09-13 12:13:31. 9736-418 the INFO [nio - 9999 - exec - 2] C.P.F ilter. Interceptor. MyInterceptor: postHandle... The 2018-09-13 12:13:31. 9736-418 the INFO [nio - 9999 - exec - 2] C.P.F ilter. Interceptor. MyInterceptor2: afterCompletion2... The 2018-09-13 12:13:31. 9736-418 the INFO [nio - 9999 - exec - 2] C.P.F ilter. Interceptor. MyInterceptor: afterCompletion...Copy the code

The difference between interceptors and filters

Interceptors and filters are very similar to each other and can handle requests from clients. The differences are as follows:

  • Different scope
    • Filters depend on the servlet container and can only be used in the servlet container, Web environment
    • The interceptor depends on the Spring container and can be invoked from the Spring container, regardless of the environment in which spring is present
  • Fine grained differences
    • Filters have coarse controls and can only be processed as requests come in, wrapping requests and responses
    • Interceptors provide finer control and can be invoked before or after the Controller processes the request, or after the render view is rendered to the user
  • The difficulty of interrupting chain execution varies
    • Interceptors canpreHandleMethod to interrupt by returning false
    • Filters are more complex, dealing with request and response objects to raise interrupts, requiring additional actions, such as redirecting the user to an error page

summary

To summarize, interceptors have more fine-grained control than filters, rely on the Spring container, can be started before or after a request, filters rely on servlets, and interceptors can do almost anything filters can do.

References & acknowledgements

  • Spring5 source code parsing – Processing interceptor in Spring
  • An in-depth look at Java Web Technology (revised edition)