博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SpringMVC解析4-DispatcherServlet逻辑脉络
阅读量:7299 次
发布时间:2019-06-30

本文共 10751 字,大约阅读时间需要 35 分钟。

HttpServlet提供了不同的服务方法,它们是doDelete(),doGet(),doOptions(),doPost(),doPut(),和doTrace(),它会根据不同的请求形式将程序引导至对应的函数进行处理。这几个函数中最常用的函数无非就是doGet()和doPost(),我们看看DispatcherServlet对着两个函数的逻辑实现。

@Override  protected final void doGet(HttpServletRequest request, HttpServletResponse response)          throws ServletException, IOException {        processRequest(request, response);  }  @Override  protected final void doPost(HttpServletRequest request, HttpServletResponse response)          throws ServletException, IOException {        processRequest(request, response);  }  protected final void processRequest(HttpServletRequest request, HttpServletResponse response)          throws ServletException, IOException {      //记录当前时间,用于计算web请求的处理时间      long startTime = System.currentTimeMillis();      Throwable failureCause = null;      //根据当前request创建对应的LocaleContext和RequestAttributes,并绑定到当前线程      LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();      LocaleContext localeContext = buildLocaleContext(request);        RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();      ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);      asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());        initContextHolders(request, localeContext, requestAttributes);        try {          //委托给doService方法进一步处理          doService(request, response);      }      catch (ServletException ex) {          failureCause = ex;          throw ex;      }      catch (IOException ex) {          failureCause = ex;          throw ex;      }      catch (Throwable ex) {          failureCause = ex;          throw new NestedServletException("Request processing failed", ex);      }        finally {          //请求处理结束后回复线程到原始状态          resetContextHolders(request, previousLocaleContext, previousAttributes);          if (requestAttributes != null) {              requestAttributes.requestCompleted();          }            if (logger.isDebugEnabled()) {              if (failureCause != null) {                  this.logger.debug("Could not complete request", failureCause);              }              else {                  if (asyncManager.isConcurrentHandlingStarted()) {                      logger.debug("Leaving response open for concurrent processing");                  }                  else {                      this.logger.debug("Successfully completed request");                  }              }          }          //请求处理结束后无论成功与否发布事件通知          publishRequestHandledEvent(request, startTime, failureCause);      }  }

函数中已经开始了对请求的处理,虽然把细节转移到了doService函数中实现,但也看得出处理请求前后所做的准备工作。

(1)为了保证当前线程的LocaleContext以及RequestAttributes可以在当前请求后还能恢复,提取当前线程的两个属性。

(2)根据当前request创建对应的LocaleContext和RequestAttributes,并绑定到当前线程。

(3)委托给doService方法进一步处理。

(4)请求处理结束后恢复线程到原始状态。

(5)请求处理结束后无论成功与否发布事件通知

继续查看doService方法。

@Override  protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {      if (logger.isDebugEnabled()) {          String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";          logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +                  " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");      }        // Keep a snapshot of the request attributes in case of an include,      // to be able to restore the original attributes after the include.      Map
attributesSnapshot = null; if (WebUtils.isIncludeRequest(request)) { attributesSnapshot = new HashMap
(); Enumeration
attrNames = request.getAttributeNames(); while (attrNames.hasMoreElements()) { String attrName = (String) attrNames.nextElement(); if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) { attributesSnapshot.put(attrName, request.getAttribute(attrName)); } } } // Make framework objects available to handlers and view objects. request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext()); request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource()); FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response); if (inputFlashMap != null) { request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap)); } request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap()); request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager); try { doDispatch(request, response); } finally { if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Restore the original attribute snapshot, in case of an include. if (attributesSnapshot != null) { restoreAttributesAfterInclude(request, attributesSnapshot); } } } }

我们猜想对请求处理至少应该包括一些诸如寻找handler并页面跳转之类的逻辑处理,但是,在doService中我们并没有看到想看到的逻辑,相反却同样是一些准备工作,但是这些准备工作是必不可少的。Spring将已经初始化的功能辅助工具变量,比如localeResolver,themeResolver等设置在request属性中,而这些属性会在接下来派上用场。doDispatch函数中展示了Spring请求处理所涉及的主要逻辑,而我们之前设置在request中的各种辅助属性也都有被派上了用场。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {      HttpServletRequest processedRequest = request;      HandlerExecutionChain mappedHandler = null;      boolean multipartRequestParsed = false;        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);        try {          ModelAndView mv = null;          Exception dispatchException = null;            try {              //如果是MultipartContent类型的request则转换request为MultipartHttpServletRequest类型的request              processedRequest = checkMultipart(request);              multipartRequestParsed = (processedRequest != request);                // Determine handler for the current request.              //根据request信息寻找对应的handler              mappedHandler = getHandler(processedRequest, false);              if (mappedHandler == null || mappedHandler.getHandler() == null) {                  //如果没有找到对应的handler则通过response反馈错误信息                  noHandlerFound(processedRequest, response);                  return;              }                // Determine handler adapter for the current request.              //根据当前的handler寻找对应的handlerAdapter              HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());                // Process last-modified header, if supported by the handler.              String method = request.getMethod();              //如果handler支持last-modified头处理              boolean isGet = "GET".equals(method);              if (isGet || "HEAD".equals(method)) {                  long lastModified = ha.getLastModified(request, mappedHandler.getHandler());                  if (logger.isDebugEnabled()) {                      logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);                  }                  if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {                      return;                  }              }              //拦截器的preHandler方法的调用              if (!mappedHandler.applyPreHandle(processedRequest, response)) {                  return;              }              // Actually invoke the handler.              //真正的激活handler并返回视图              mv = ha.handle(processedRequest, response, mappedHandler.getHandler());                if (asyncManager.isConcurrentHandlingStarted()) {                  return;              }              //视图名称转换应用于需要添加前缀后缀的情况              applyDefaultViewName(request, mv);              //调用所有拦截器的postHandle方法              mappedHandler.applyPostHandle(processedRequest, response, mv);          }          catch (Exception ex) {              dispatchException = ex;          }          //页面处理          processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);      }      catch (Exception ex) {          triggerAfterCompletion(processedRequest, response, mappedHandler, ex);      }      catch (Error err) {          triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);      }      finally {          if (asyncManager.isConcurrentHandlingStarted()) {              // Instead of postHandle and afterCompletion              if (mappedHandler != null) {                  mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);              }          }          else {              // Clean up any resources used by a multipart request.              if (multipartRequestParsed) {                  cleanupMultipart(processedRequest);              }          }      }  }  private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,          HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {      boolean errorView = false;      if (exception != null) {          if (exception instanceof ModelAndViewDefiningException) {              logger.debug("ModelAndViewDefiningException encountered", exception);              mv = ((ModelAndViewDefiningException) exception).getModelAndView();          }          else {              Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);              mv = processHandlerException(request, response, handler, exception);              errorView = (mv != null);          }      }      // Did the handler return a view to render?      if (mv != null && !mv.wasCleared()) {          //处理页面跳转          render(mv, request, response);          if (errorView) {              WebUtils.clearErrorRequestAttributes(request);          }      }      else {          if (logger.isDebugEnabled()) {              logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +                      "': assuming HandlerAdapter completed request handling");          }      }      if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {          // Concurrent handling started during a forward          return;      }      if (mappedHandler != null) {          //完成激活处理触发器          mappedHandler.triggerAfterCompletion(request, response, null);      }  }

Spring每一步是怎么处理dispatcher中的方法的,在下面一节分析。

 

转载地址:http://ijwnm.baihongyu.com/

你可能感兴趣的文章
IT实用技术资源整理
查看>>
在datalist中实现“删除”功能的三种方法
查看>>
POM标签大全详解
查看>>
Hibernate数据查询(转)
查看>>
[HAOI2016]放棋子
查看>>
bzoj4367-[IOI2014]holiday假期
查看>>
JNI的调试_从java代码连调到C/C++
查看>>
centos忘了root用户密码
查看>>
在Visual Studio中使用.lib和.dll的环境搭建
查看>>
form表单的button
查看>>
正则表达式(更新中。。。)
查看>>
2017年终总结
查看>>
问题账户需求分析
查看>>
Notepad++ 配置信息导出导入(快捷键配置导出导入等等)
查看>>
adb命令--之查看进程及Kill进程
查看>>
AI - H2O - 第一个示例
查看>>
schedule调用相关整理
查看>>
[HDU6155]Subsequence Count
查看>>
Javascript 实现简单计算器实例代码
查看>>
数论概论(Joseph H.Silverman) 定理39.1 连分数的递归公式
查看>>