When working with A Web framework, you can’t avoid dealing with these concepts, so let’s wrap things up and go through interceptors, filters, listeners.

GitHub source address

1. Differences between interceptors, filters, and listeners

  • Interceptor: Depends on the Web framework, based on Java reflection mechanism, belongs to a kind of AOP application. An interceptor instance can be called multiple times during a controller life cycle. Only Controller requests can be intercepted.
  • Filters: Rely on the Servlet container, based on function callback, can be filtered for almost any request, a Filter instance can only be invoked once in the container initialization.
  • Listeners: Web listeners are special classes in servlets that listen for specific events on the Web. They are started with the Web application and initialized only once.

2. What’s the use

  • Interceptor: When a request is in progress, you want to interfere with its progress and even control whether it is terminated. That’s what interceptors do.
  • Filter: When you have a bunch of things, you only want to select the things that fit. The tool that defines these requirements is the filter.
  • Listener: After an event occurs, you only want to obtain the details of the occurrence of the event without interfering with the execution of the event

3. Startup sequence

Listener > Filter > InterceptorCopy the code

4. Specific implementation in SpringBoot

(1) Interceptor

  1. Interceptors are commonly implemented in two ways
    • Implement the HandlerInterceptor interface
    • Inheritance HandlerInterceptorAdapter abstract classes
  2. Distinction and connection
  • HandlerInterceptorAdapter AsyncHandlerInterceptor interface, AsyncHandlerInterceptor interface inheritance HandlerInterceptor interface.
  • More than a afterConcurrentHandlingStarted method AsyncHandlerInterceptor interface
  1. The specific methods
  • PreHandle // The first method to go after the request returns true to continue execution
  • PostHandle // request after return before
  • AfterCompletion // After processing is complete
  • AfterConcurrentHandlingStarted / / if it returns a current type of variable, will enable a new thread. Immediately after execution preHandle method will be called afterConcurrentHandlingStarted, and then a new thread successively performed preHandle, postHandle, afterCompletion
  1. Code implementation

The following code is based on springboot2.0

(1) the interceptor

MyInterceptor1 inheritance HandlerInterceptorAdapter

MyInterceptor2 implements the HandlerInterceptor interface

public class MyInterceptor1 extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        request.setAttribute("startTime", System.currentTimeMillis());
        System.out.println(">>>>> MyInterceptor1 preHandle >>>>>>>>>>>>>>>>>>>>>>");
        return super.preHandle(request, response, handler);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        long startTime = (long) request.getAttribute("startTime");
        System.out.println("MyInterceptor1 execution." + (System.currentTimeMillis() - startTime));
        System.out.println(">>>>> MyInterceptor1 postHandle >>>>>>>>>>>>>>>>>>>>>>");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        request.removeAttribute("startTime");
        System.out.println(">>>>> MyInterceptor1 afterCompletion >>>>>>>>>>>>>>>>>>>>>>");
    }

    @Override
    public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        super.afterConcurrentHandlingStarted(request, response, handler);
        System.out.println(">>>>> MyInterceptor1 afterConcurrentHandlingStarted >>>>>>>>>>>>>>>>>>>>>>"); }}Copy the code
public class MyInterceptor2 implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        request.setAttribute("startTime", System.currentTimeMillis());
        System.out.println(">>>>> MyInterceptor2 preHandle >>>>>>>>>>>>>>>>>>>>>>");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        long startTime = (long) request.getAttribute("startTime");
        System.out.println("MyInterceptor2 execution." + (System.currentTimeMillis() - startTime));
        System.out.println(">>>>> MyInterceptor2 postHandle >>>>>>>>>>>>>>>>>>>>>>");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        request.removeAttribute("startTime");
        System.out.println(">>>>> MyInterceptor2 afterCompletion >>>>>>>>>>>>>>>>>>>>>>"); }}Copy the code

(2) configuration

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor1()).addPathPatterns("/ * *");
        registry.addInterceptor(new MyInterceptor2()).addPathPatterns("/ * *"); }}Copy the code

(3) request

@RestController
@SpringBootApplication
public class SpringbootInterceptorApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootInterceptorApplication.class, args);
    }


    @GetMapping(value = "/hello1")
    public ResponseEntity<String> hello(a) throws InterruptedException {
        Thread.sleep(500);
        return ResponseEntity.ok("HelloWorld");
    }

    @GetMapping(value = "/hello2")
    public StreamingResponseBody hello2(a) throws InterruptedException {
        Thread.sleep(500);
        return (OutputStream outputStream) -> {
            outputStream.write("success".getBytes());
            outputStream.flush();
            outputStream.close();
        };
    }

    @GetMapping(value = "/hello3")
    public Future<String> hello3(a) throws InterruptedException {
        Thread.sleep(500);
        return new AsyncResult<>("Hello"); }}Copy the code

(4) Running results

  1. Request/hello1

    >>>>> MyInterceptor1 preHandle >>>>>>>>>>>>>>>>>>>>>> >>>>> MyInterceptor2 preHandle >>>>>>>>>>>>>>>>>>>>>> MyInterceptor2 :516 >>>>> MyInterceptor2 postHandle >>>>>>>>>>>>>>>>>>>>> MyInterceptor1 :516 >>>>> MyInterceptor1 postHandle >>>>>>>>>>>>>>>>>>>>> >>>>> MyInterceptor2 afterCompletion >>>>>>>>>>>>>>>> >>>>> MyInterceptor1 afterCompletion >>>>>>>>>>>>>>>>Copy the code

    To execute, press preHandle > postHandle > afterCompletion

  2. Request /hello2 or /hello3

    >>>>> MyInterceptor1 preHandle >>>>>>>>>>>>>>>>>>>>>> >>>>> MyInterceptor2 preHandle >>>>>>>>>>>>>>>>>>>>>> >>>>> MyInterceptor1 afterConcurrentHandlingStarted >>>>>>>>>>>>>>>>>>>>>> >>>>> MyInterceptor1 preHandle > > > > > > > > > > > > > > > > > > > > > > > > > > > MyInterceptor2 preHandle > > > > > > > > > > > > > > > > > > > > > > MyInterceptor2 execution: 1 > > > > > MyInterceptor2 PostHandle > > > > > > > > > > > > > > > > > > > > > > MyInterceptor1 execution: 1 > > > > > MyInterceptor1 postHandle > > > > > > > > > > > > > > > > > > > > > > > > > > > MyInterceptor2 afterCompletion >>>>>>>>>>>>>>>>>>>>>> >>>>> MyInterceptor1 afterCompletion >>>>>>>>>>>>>>>>>>>>>>Copy the code

    MyInterceptor1 execution order preHandle > afterConcurrentHandlingStarted > preHandle > postHandle > afterCompletion

    MyInterceptor2 Order of execution preHandle > preHandle > postHandle > afterCompletion

For a return value of a Concurrent type, Spring starts a new thread to process the concurrent message, in which the preHandle method is called again.

(2) filter

(1) filter

public class MyFilter1 implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println(filterConfig.getInitParameter("initParam"));
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("doFilter1 >>>>>>>>>>>"); filterChain.doFilter(servletRequest, servletResponse); }}Copy the code

(2) configuration

  • The first way
@Bean
public FilterRegistrationBean<MyFilter1> filterRegistrationBean(a) {
    FilterRegistrationBean<MyFilter1> filterRegistrationBean = new FilterRegistrationBean<>();
    filterRegistrationBean.addUrlPatterns("/ *");// Filter all
    filterRegistrationBean.setFilter(new MyFilter1());
    filterRegistrationBean.setOrder(1);
    filterRegistrationBean.addInitParameter("initParam"."initOk");
    return filterRegistrationBean;
}
Copy the code
  • The second way
@Bean
public MyFilter1 myFilter(a) {
    return new MyFilter1();
}
Copy the code
  • The third way
@WebFilter("/test/*")
public class MyFilter2 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("MyFilter2");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("DoFilter 2"); }}Copy the code

@servletComponentScan (“com.jiuxian”) ¶

Note that the configuration of Filter global Interceptor(/*) is different from that of Interceptor(/**)

(3) Listener

(1) the listener

public class MyListener1 implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("MyListener1 ... "); }}Copy the code

(2) The configuration mode is similar to Filter

  • The first way
 @Bean
public ServletListenerRegistrationBean<MyListener1> registrationBean(a) {
    ServletListenerRegistrationBean<MyListener1> servletListenerRegistrationBean
            = new ServletListenerRegistrationBean<>();
    servletListenerRegistrationBean.setListener(new MyListener1());
    return servletListenerRegistrationBean;
}
Copy the code
  • The second way
@Bean
public MyListener1 myListener1(a) {
    return new MyListener1();
}
Copy the code
  • The third way
@WebListener
public class MyListener2 implements ServletRequestListener {

    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        System.out.println("MyListener2"); }}Copy the code

To use the @webListener annotation, you first need @ServletComponentScan(“com.jiuxian”).

[note] the above code is based on springboot2.0

GitHub source address