Overall flow

  • All requests are intercepted to DispatcherServlet , which is also a Servlet , executing doService .
  • Snapshot all the parameters in the request and set some objects in the framework to the request object.
  • Call the doDispatch(request,response) method.
  • Call the getHandler method to get the corresponding Handler.
  • Call getHandlerAdapter to get the corresponding HandlerAdapter.
  • Apply the interceptor’s PreHandler, or return it directly if the interceptor’s PreHandeler returns false.
  • Call the handler of the HandlerAdapter object to get the ModelAndView object.
  • Apply the postHandle method of the interceptor.
  • Call processDispatchResult to process the result, which internally calls the interceptor’s afterCompletion method.

Source code details

How do I get the corresponding Handler?

Getting the Handler is done through the getHandler method.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
 for (HandlerMapping hm : this.handlerMappings) {
  if (logger.isTraceEnabled()) {
   logger.trace(
     "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
  }
  HandlerExecutionChain handler = hm.getHandler(request);
  if (handler != null) {
   return handler;
  }
 }
 return null;
}

This code looks very simple, it iterates through handlerMappings, and gets HandlerExecutionChain from HandlerMapping which is our handler .

This HandlerExecutionChain contains the handler and HandlerInterceptor arrays. That is, we get handler which is actually a chain of processes.

Why do we need HandlerAdapter and how does it get it?

SpringMVC’s handler is implemented in more ways, such as by inheriting from Controller, by annotating the controller, and by HttpRequestHandler. Because the implementation of handler is different, the way to call it is also uncertain. So HandlerAdapter is introduced for adaptation.

The HandlerAdapter interface has three methods.

1
2
3
4
//判断当前的HandlerAdapter是否支持HandlerMethod
boolean supports(Object handler);
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
long getLastModified(HttpServletRequest request, Object handler);

Getting a HandlerAdapter is done through the getHandlerAdapter method. By analyzing the HandlerAdapter source code. We can see that HandlerAdapter actually finds a currently supported handler from the HandlerAdapter list.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
 for (HandlerAdapter ha : this.handlerAdapters) {
  if (logger.isTraceEnabled()) {
   logger.trace("Testing handler adapter [" + ha + "]");
  }
  if (ha.supports(handler)) {
   return ha;
  }
 }
 throw new ServletException("No adapter for handler [" + handler +
   "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

This method simply iterates through the HandlerAdapter list, finds one that supports the current handler, and returns it.

The handler method execution process

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
   throws Exception {

//最终拿到了我们的Controller类
  Class<?> clazz = ClassUtils.getUserClass(handler);
  //判断是否使用了@SessionAttributes
  Boolean annotatedWithSessionAttributes = this.sessionAnnotatedClassesCache.get(clazz);
  if (annotatedWithSessionAttributes == null) {
   annotatedWithSessionAttributes = (AnnotationUtils.findAnnotation(clazz, SessionAttributes.class) != null);
   this.sessionAnnotatedClassesCache.put(clazz, annotatedWithSessionAttributes);
  }

  if (annotatedWithSessionAttributes) {
   // Always prevent caching in case of session attribute management.
   checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
   // Prepare cached set of session attributes names.
  }
  else {
   // 禁用缓存
   checkAndPrepare(request, response, true);
  }

  // Execute invokeHandlerMethod in synchronized block if required.
  if (this.synchronizeOnSession) {
   HttpSession session = request.getSession(false);
   if (session != null) {
    Object mutex = WebUtils.getSessionMutex(session);
    synchronized (mutex) {
     return invokeHandlerMethod(request, response, handler);
    }
   }
  }

  return invokeHandlerMethod(request, response, handler);
 }

Finally it comes to the invokerhandlerMethod method.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler)
   throws Exception {

  ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);
  //获取处理请求的方法
  Method handlerMethod = methodResolver.resolveHandlerMethod(request);
  //创建各种组件
  ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);
  ServletWebRequest webRequest = new ServletWebRequest(request, response);
  ExtendedModelMap implicitModel = new BindingAwareModelMap();

        //调用方法拿到结果
  Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
  //获取ModelAndView
  ModelAndView mav =
    methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);
  //更新view中的属性
  methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);
  return mav;
 }

Finally call mappedHandler.applyPostHandle(processedRequest, response, mv); for post-processing. The post-processing process is to call all the post-interceptors for processing.

Filter and Interceptor

The way Filter is implemented

Implement the Filter interface

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
@WebFilter(filterName = "filterOne", urlPatterns = {"/*"})
public class FilterOne implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("===========before doFilter");
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("===========after doFilter");
    }

    @Override
    public void destroy() {
        System.out.println("destroy");
    }
}

Implementation of Interceptor

Implement the HandlerInterceptor interface.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("Controller调用之前的拦截器。。。");
        return true;
    }

    /**
     * 该方法controller调用之后,页面渲染之前执行,要preHandler返回ture才会执行该方法
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

        System.out.println("controller调用之后,页面渲染之前执行");
    }


    /**请求完成之后执行的拦截器,要preHandler返回ture才会执行该方法
     * 
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

        System.out.println("请求完成之后执行的拦截器");
    }
}

Configure it in the springmvc configuration file.

1
2
3
4
5
6
7
8
9
<mvc:interceptors>  
    <!-- 使用bean定义一个Interceptor,直接定义在mvc:interceptors根下面的Interceptor将拦截所有的请求 -->  
    <bean class="com.host.app.web.interceptor.AllInterceptor"/>  
    <mvc:interceptor>  
        <mvc:mapping path="/test/number.do"/>  
        <!-- 定义在mvc:interceptor下面的表示是对特定的请求才进行拦截的 -->  
        <bean class="com.host.app.web.interceptor.LoginInterceptor"/>  
    </mvc:interceptor>  
</mvc:interceptors>

Similarities

  • Both can intercept requests and filter them
  • Both apply the filter (chain of responsibility) design pattern

Differences

  • Filter filters are more accessible and are configured in web.xml
  • Interceptor is smaller in scope and is configured in springmvc
  • Before going to springmvc processing, first process web.xml

Reference https://zofun.github.io/2020/05/20/%E8%B7%9F%E8%B8%AASpringMVC%E8%AF%B7%E6%B1%82%E8%BF%87%E7%A8%8B/