跟踪SpringMVC请求过程

原文转载自 「个人博客」 ( https://zofun.github.io/2020/05/20/跟踪SpringMVC请求过程/ ) By 爱写代码的小书童

预计阅读时间 0 分钟(共 0 个字, 0 张图片, 0 个链接)

整体流程

  1. 所有的请求都被拦截到DispatcherServlet,它也是一个Servlet,执行doService
  2. 快照请求中的所有的参数,将框架中的一些对象设置到request对象中。
  3. 调用doDispatch(request,response)方法
  4. 调用getHandler方法获取对应的Handler
  5. 调用getHandlerAdapter拿到对应的HandlerAdapter
  6. 应用拦截器的PreHandler,如果拦截器的PreHandeler返回false,则直接返回
  7. 调用HandlerAdapter对象的handler得到ModelAndView对象
  8. 应用拦截器的postHandle方法
  9. 调用processDispatchResult对结果进行处理,其内部调用了拦截器的afterCompletion方法

源码细节

如何拿到对应的Handler?

获取Handler是通过getHandler方法来获取的。

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;
}

这段代码看起来非常的简单,遍历handlerMappings,从HandlerMapping从获取HandlerExecutionChain即我们的handler.

这个HandlerExecutionChain中包含了handlerHandlerInterceptor数组。也就是我们拿到handler实际上是一个处理链。

为什么需要HandlerAdapter,它的如何获取到的?

SpringMVC的handler的实现方式比较的多,比如通过继承Controller的,基于注解控制器方式,HttpRequestHandler的方式。因为handler的实现方式不同,因此调用的方式也就不确定了。因此引入了HandlerAdapter来进行适配。
HandlerAdapter接口有三个方法:

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);

获取HandlerAdapter是通过getHandlerAdapter方法来获取的。通过对HandlerAdapter使用原因的分析,我们可以直到所谓获取对应的HandlerAdapter实际上从HandlerAdapter列表中找出一个支持当前handler的。

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");
}

该方法就是简单的遍历HandlerAdapter列表,从中找出一个支持当前handler的,并返回。

handler方法的执行过程

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);
}

最终来到了invokerhandlerMethod方法了:

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;
}

最后调用mappedHandler.applyPostHandle(processedRequest, response, mv);进行后处理。后处理的过程就是调用所有的后置拦截器进行处理。

Filter与Interceptor

Filter的实现方式

  1. 实现Filter接口

    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");
    }
    }

Interceptor的实现方式

  1. 实现HandlerInterceptor接口

    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("请求完成之后执行的拦截器");
    }
    }
  2. springmvc的配置文件中进行配置

    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>

相同点

区别

more_vert