4

跟踪SpringMVC请求过程

 3 years ago
source link: 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/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

跟踪SpringMVC请求过程

2020-05-20

  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方法来获取的。

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接口有三个方法:

//判断当前的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的。

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方法的执行过程

	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方法了:

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接口

    @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接口

    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的配置文件中进行配置

    <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>
  • 都可以拦截请求,过滤请求
  • 都是应用了过滤器(责任链)设计模式
  • Filter过滤器访问较大,配置在web.xml
  • Interceptor范围比较小,配置在springmvc
  • 在进入springmvc处理之前,首先要处理web.xml

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK