Q: Use filters, interceptors and slices to calculate the time of each request, and compare the differences and relationships among the three

Filter Filter

Filter concept

Filter is J2E, can be seen as a “enhanced version” of Servlet, it is mainly used for user requests for pre-processing and post-processing, with a typical processing chain. Filters can also generate responses to user requests, like servlets, but in practice they are rarely used to generate responses to user requests. The complete process of using Filter is: Filter preprocesses the user request, then sends the request to the Servlet for preprocessing and generating the response, and finally Filter postprocesses the server response.

Filter action

The role of several filters is described in JavaDoc

 * Examples that have been identified forThis design is <br> * 1) Authentication Filters * 2) Logging and Auditing Filters, * 3) Image conversion Filters * 4) Data compression Filters <br> * 5) Encryption Filters <br> * 6) Tokenizing Filters <br> * 7) Filters that trigger resource access events <br> * 8) XSL/T filters <br> * 9) Mime-type chain Filter <br>Copy the code

For the first one, that is, Filter is used for permission filtering, which can be implemented as follows: Define a Filter to obtain the URL of each request initiated by the client and compare it with the LIST of urls (which can be retrieved from DB) that the current user does not have permission to access, so as to play the role of permission filtering.

Filter implementation

Custom filters must implement the Javax.servlet. Filter interface and override the three methods defined in the interface:

  1. void init(FilterConfig config)

    This parameter is used to initialize the Filter.
  2. void destory()

    Used to recycle some resources before Filter destruction.
  3. void doFilter(ServletRequest request,ServletResponse response,FilterChain chain)

    Implement filtering capabilities that add additional pre – and post-processing to each request and response. Before executing the method, the user request is preprocessed; After this method is executed, the server response is postprocessed. It’s worth noting that,chain.doFilter()The pre-processing stage is before the execution of the method. The end of the execution of the method means that the user’s request has been processed by the controller. Therefore, if againdoFilterForget to call inchain.doFilter()Method, the user’s request will not be processed.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

// Annotations must be added, springMVC is configured via web.xml
@Component
public class TimeFilter implements Filter {
    private static final Logger LOG = LoggerFactory.getLogger(TimeFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        LOG.info("Initialize filter: {}", filterConfig.getFilterName());
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        LOG.info("start to doFilter");
        long startTime = System.currentTimeMillis();
        chain.doFilter(request, response);
        long endTime = System.currentTimeMillis();
        LOG.info("the request of {} consumes {}ms.", getUrlFrom(request), (endTime - startTime));
        LOG.info("end to doFilter");
    }

    @Override
    public void destroy(a) {
        LOG.info("Destroy filter");
    }

    private String getUrlFrom(ServletRequest servletRequest){
        if (servletRequest instanceof HttpServletRequest){
            return ((HttpServletRequest) servletRequest).getRequestURL().toString();
        }

        return ""; }}Copy the code

As you can see from the code, the Filter class is in Javax.servlet.*, so you can see that a major limitation of the Filter is that it cannot know which Controller (Controller) the current user request is being processed by, as defined in the Spring framework.

Register third-party filters in SpringBoot

For SpringMvc, you can register filters in web.xml. But there is no web.xml in SpringBoot, and if a filter is referenced in a JAR package that is not identified as a Spring Bean with @Component when implemented, the filter will not take effect. At this point, you need to register the filter with Java code. Taking the TimeFilter defined above as an example, when the @component class annotation is removed, it is registered as follows:

@Configuration
public class WebConfig {
    /** * Registering third-party filters * functions the same as in Spring MVC by configuring web.xml *@return* /
    @Bean
    public FilterRegistrationBean thirdFilter(a){
        ThirdPartFilter thirdPartFilter = new ThirdPartFilter();
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean() ;

        filterRegistrationBean.setFilter(thirdPartFilter);
        List<String > urls = new ArrayList<>();
        // Match all request paths
        urls.add("/ *");
        filterRegistrationBean.setUrlPatterns(urls);

        returnfilterRegistrationBean; }}Copy the code

One advantage of this configuration over the @Component annotation is that you can freely configure the urls to be intercepted.

The Interceptor Interceptor

Interceptor concept

Interceptor, used in AOP(aspect-oriented Programming) to intercept a method or field before it is accessed and then add some action before or after. Interception is an implementation strategy of AOP.

Interceptor role

  1. Log: Logs request information for information monitoring, statistics collection, and Page View (PV) calculation
  2. Permission check: For example, login check, enter the processor to check whether you are logged in
  3. Performance monitoring: The processing time of the request is obtained by the interceptor recording the start time before entering the processor and the end time after processing. (Reverse proxies such as Apache can also record automatically);
  4. Common behavior: Read cookies to get user information and put user objects into the request for use by subsequent processes, as well as extracting Locale, Theme information, etc., which are required by multiple processors, can be implemented using interceptors.

Interceptor implementation

By implementing the HandlerInterceptor interface and rewriting the interface’s three methods, we can customize the interceptor:

  1. preHandler(HttpServletRequest request, HttpServletResponse response, Object handler)

    Methods inPrior to request processingCall. For SpringMVC inInterceptorIt’s the same thing as FilterChain calls. Each Interceptor call is executed in the order in which it is declared, and the first one is the Interceptor preHandle method, so some pre-initialization or a pre-processing of the current request can be done in this method. You can also make some judgments in this method to determine whether the request should proceed. The return value of this method is Boolean. When it returns false, the request is complete. The Interceptor and Controller will not be returned. When the return value is true, the next Interceptor’s preHandle method is called, and the requested Controller method is called when the last Interceptor is intercepted.
  2. postHandler(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)

    In the currentAfter the request is processedThat is, after the Controller method is called, but it will be called before the DispatcherServlet does the view return rendering, so we can operate on the ModelAndView object after the Controller process in this method.
  3. afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex)

    This method is executed only when the corresponding Interceptor’s preHandle method returns true. As the name implies, this method will end after the entire request, which is in the DispatcherServletExecute after rendering the corresponding view. The main purpose of this method is for resource cleanup.
@Component
public class TimeInterceptor implements HandlerInterceptor {
    private static final Logger LOG = LoggerFactory.getLogger(TimeInterceptor.class);
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        LOG.info("Call before request processing (before Controller method call)");
        request.setAttribute("startTime", System.currentTimeMillis());
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        LOG.info("controller object is {}", handlerMethod.getBean().getClass().getName());
        LOG.info("controller method is {}", handlerMethod.getMethod());

        // Return true otherwise the request will not be processed by the controller
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        LOG.info("Called after the request is processed, but not until the view is rendered (after the Controller method is called) if an exception occurs.");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        LOG.info("Called at the end of the entire request, which is executed after the DispatcherServlet renders the corresponding view (mainly for resource cleanup)");
        long startTime = (long) request.getAttribute("startTime");
        LOG.info("time consume is {}", System.currentTimeMillis() - startTime);
    }
Copy the code

Unlike filters, interceptors decorated with @Component also need to be manually registered in SpringBoot by implementing WebMvcConfigurer:

// Java configuration class
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private TimeInterceptor timeInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry){ registry.addInterceptor(timeInterceptor); }}Copy the code

If you are in SpringMVC, you need to configure the < MVC: Interceptors > node information through an XML file.

Slice the Aspect

Overview section

Compared to filters, interceptors can know which controller will process the request sent by the user, but there is an obvious disadvantage of interceptors, that is, they cannot get the parameters of the request and the response after the controller processes it. So that’s where slicing comes in.

Slice to realize

The implementation of slicing requires the use of @aspect, @component, and @around annotations. Check out the official documentation: Portal

@Aspect
@Component
public class TimeAspect {
    private static final Logger LOG = LoggerFactory.getLogger(TimeAspect.class);

    @Around("execution(* me.ifight.controller.*.*(..) )")
    public Object handleControllerMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        LOG.info("Slices begin...");
        long startTime = System.currentTimeMillis();

        // Get the request input parameter
        Object[] args = proceedingJoinPoint.getArgs();
        Arrays.stream(args).forEach(arg -> LOG.info("arg is {}", arg));

        // Get the corresponding
        Object response = proceedingJoinPoint.proceed();

        long endTime = System.currentTimeMillis();
        LOG.info("Request :{}, time {}ms", proceedingJoinPoint.getSignature(), (endTime - startTime));
        LOG.info("End of slice...");
        return null; }}Copy the code

Call order for filters, interceptors, and slices

The following figure shows the call order of the three filters ->Intercepto->Aspect->Controller. In contrast, exceptions thrown by the Controller are handled from the inside out. So we always define an annotation @ControllerAdvice to handle all the exceptions thrown by the controller. If once the Exception is handled by @Controlleradvice, the Exception ex argument to the afterCompletion method that calls the interceptor is empty.

The difference between filters and interceptors

Finally, it’s worth mentioning the differences between filters and interceptors:

Filter Interceptor
implementation Filters are based on function callbacks Java-based reflection mechanism
specification The Servlet specification Spring specification
scope It works on almost all requests This only works on action requests

In addition, interceptors can “see” which controller of the Spring framework is handling a user’s request, as opposed to filters.

reference

Blog.csdn.net/xiaodanjava…