经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring » 查看文章
Java?spring?mvc请求详情介绍
来源:jb51  时间:2022/3/29 16:18:58  对本文有异议

前言:

  • 本文源码基于spring-framework-5.3.10
  • mvcspring源码中的一个子模块!

一、源码执行流程

  • 用户发送请求至前端控制器DispatcherServlet。
  • DispatcherServlet收到请求调用处理器映射器HandlerMapping。处理器映射器根据请求url找到具体的处理器,生成处理器执行链HandlerExecutionChain(包括处理器对象和处理器拦截器)一并返回给DispatcherServlet。
  • DispatcherServlet根据处理器Handler获取处理器适配器HandlerAdapter,执行HandlerAdapter处理一系列的操作,如:参数封装,数据格式转换,数据验证等操作
  • 执行处理器Handler(Controller,也叫页面控制器)。Handler执行完成返回ModelAndViewHandlerAdapter将Handler执行结果ModelAndView返回到DispatcherServlet。
  • DispatcherServletModelAndView传给ViewReslover视图解析器。ViewReslover解析后返回具体View
  • DispatcherServlet对View进行渲染视图(即将模型数据model填充至视图中)。
  • DispatcherServlet响应用户。

二、源码执行流程图

三、spring mvc中的一核心组件

  • DispatcherServlet: 前端调度器 , 负责将请求拦截下来分发到各控制器方法中
  • HandlerMapping: 负责根据请求的URL和配置@RequestMapping映射去匹配, 匹配到会返回Handler(具体控制器的方法)
  • HandlerAdaper: 负责调用Handler-具体的方法- 返回视图的名字 Handler将它封装到ModelAndView(封装视图名,request域的数据)
  • ViewReslover: 根据ModelAndView里面的视图名地址去找到具体的jsp封装在View对象中
  • View:进行视图渲染(将jsp转换成html内容 --这是Servlet容器的事情了) 最终response到的客户端

四、源码分析

  1. /**
  2. * 最核心的控制器
  3. * 源码位置:org.springframework.web.servlet.DispatcherServlet.doDispatch(HttpServletRequest, HttpServletResponse)
  4. */
  5. protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
  6. HttpServletRequest processedRequest = request;
  7. HandlerExecutionChain mappedHandler = null;
  8. boolean multipartRequestParsed = false;
  9.  
  10. WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
  11.  
  12. try {
  13. ModelAndView mv = null;
  14. Exception dispatchException = null;
  15.  
  16. try {
  17. // 验证是不是上传的请求,上传的请求会转化为MultipartHttpServletRequest
  18. processedRequest = checkMultipart(request);
  19. multipartRequestParsed = (processedRequest != request);
  20.  
  21. // 进行映射
  22. mappedHandler = getHandler(processedRequest);
  23. if (mappedHandler == null) {
  24. noHandlerFound(processedRequest, response);
  25. return;
  26. }
  27.  
  28. // 找到最合适的HandlerAdapter,按照顺序,那个先解析到就是那个
  29. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
  30.  
  31. // Process last-modified header, if supported by the handler. HTTP缓存相关
  32. String method = request.getMethod();
  33. boolean isGet = HttpMethod.GET.matches(method);
  34. if (isGet || HttpMethod.HEAD.matches(method)) {
  35. long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
  36. if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
  37. return;
  38. }
  39. }
  40. // 前置拦截器
  41. if (!mappedHandler.applyPreHandle(processedRequest, response)) {
  42. // 返回false就不进行后续处理了
  43. return;
  44. }
  45.  
  46. // Actually invoke the handler.
  47. // 获取参数,执行方法
  48. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
  49.  
  50. if (asyncManager.isConcurrentHandlingStarted()) {
  51. return;
  52. }
  53. // 如果mv有 视图没有,给你设置默认视图
  54. applyDefaultViewName(processedRequest, mv);
  55. //后置拦截器
  56. mappedHandler.applyPostHandle(processedRequest, response, mv);
  57. }
  58. catch (Exception ex) {
  59. dispatchException = ex;
  60. }
  61. catch (Throwable err) {
  62. // As of 4.3, we're processing Errors thrown from handler methods as well,
  63. // making them available for @ExceptionHandler methods and other scenarios.
  64. dispatchException = new NestedServletException("Handler dispatch failed", err);
  65. }
  66. // 渲染视图
  67. processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
  68. }
  69. catch (Exception ex) {
  70. triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
  71. }
  72. catch (Throwable err) {
  73. triggerAfterCompletion(processedRequest, response, mappedHandler,
  74. new NestedServletException("Handler processing failed", err));
  75. }
  76. finally {
  77. if (asyncManager.isConcurrentHandlingStarted()) {
  78. // Instead of postHandle and afterCompletion
  79. if (mappedHandler != null) {
  80. mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
  81. }
  82. }
  83. else {
  84. // Clean up any resources used by a multipart request.
  85. if (multipartRequestParsed) {
  86. cleanupMultipart(processedRequest);
  87. }
  88. }
  89. }
  90. }

五、获取组件相关逻辑:

原理:谁先解析到就用谁!

  1. /**
  2. * 获取处理器映射器
  3. * 源码位置:org.springframework.web.servlet.DispatcherServlet.getHandler(HttpServletRequest)
  4. */
  5. protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  6. if (this.handlerMappings != null) {
  7. /** 拿到所有handlerMappings (容器启动阶段初始化:拿到所有实现了HandlerMapping的Bean)
  8. * @see DispatcherServlet#initHandlerMappings
  9. * 测试发现: 不同的HandlerMapping可以有相同path, 谁先解析到就用哪个
  10. * */
  11. for (HandlerMapping mapping : this.handlerMappings) {
  12. HandlerExecutionChain handler = mapping.getHandler(request);
  13. if (handler != null) {
  14. return handler;
  15. }
  16. }
  17. }
  18. return null;
  19. }
  20.  
  21. /**
  22. * 获取处理器适配器
  23. * 源码位置:org.springframework.web.servlet.DispatcherServlet.getHandlerAdapter(Object)
  24. */
  25. protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
  26. if (this.handlerAdapters != null) {
  27. // 按照配置的顺序,谁先解析到就用那个
  28. for (HandlerAdapter adapter : this.handlerAdapters) {
  29. if (adapter.supports(handler)) {
  30. return adapter;
  31. }
  32. }
  33. }
  34. throw new ServletException("No adapter for handler [" + handler +
  35. "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
  36. }

六、获取参数,执行方法源码分析

  1. /**
  2. * 获取参数,执行方法最外层的调用
  3. * 源码位置:org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(HttpServletRequest, HttpServletResponse, Object)
  4. */
  5. public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
  6. throws Exception {
  7. // 直接调用这个方法
  8. return handleInternal(request, response, (HandlerMethod) handler);
  9. }
  10.  
  11. /**
  12. * 获取参数,执行方法内部的调用逻辑
  13. * 源码位置:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(HttpServletRequest, HttpServletResponse, HandlerMethod)
  14. */
  15. protected ModelAndView handleInternal(HttpServletRequest request,
  16. HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
  17.  
  18. ModelAndView mav;
  19. // 检查当前请求的method是否为支持的method(默认Null,可通过继承AbstractController设置supportedMethods)
  20. // 检查当前请求是否必须session (默认false,可通过继承AbstractController设置requireSession)
  21. checkRequest(request);
  22.  
  23. /**
  24. * 判断当前是否需要支持在同一个session中只能线性地处理请求:一个session同时只能处理一个线程
  25. * 因为锁是通过 synchronized 是 JVM 进程级,所以在分布式环境下,
  26. * 无法达到同步相同 Session 的功能。默认情况下,synchronizeOnSession 为 false
  27. */
  28. if (this.synchronizeOnSession) {
  29. // 获取当前请求的session对象
  30. HttpSession session = request.getSession(false);
  31. if (session != null) {
  32. // 为当前session生成一个唯一的可以用于锁定的key
  33. Object mutex = WebUtils.getSessionMutex(session);
  34. synchronized (mutex) {
  35. // 对HandlerMethod进行参数等的适配处理,并调用目标handler
  36. mav = invokeHandlerMethod(request, response, handlerMethod);
  37. }
  38. }
  39. else {
  40. // 如果当前不存在session,则直接对HandlerMethod进行适配
  41. mav = invokeHandlerMethod(request, response, handlerMethod);
  42. }
  43. }
  44. else {
  45. // *如果当前不需要对session进行同步处理,则直接对HandlerMethod进行适配
  46. mav = invokeHandlerMethod(request, response, handlerMethod);
  47. }
  48.  
  49.  
  50. //判断当前请求头中是否包含Cache-Control请求头,如果不包含,则对当前response进行处理
  51. if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
  52. // 如果当前SessionAttribute中存在配置的attributes,则为其设置过期时间。
  53. // 这里SessionAttribute主要是通过@SessionAttribute注解生成的
  54. if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
  55. applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
  56. }
  57. else {
  58. // 如果当前不存在SessionAttributes,则判断当前是否存在Cache-Control设置,
  59. // 如果存在,则按照该设置进行response处理,如果不存在,则设置response中的
  60. // Cache的过期时间为-1,即立即失效
  61. prepareResponse(response);
  62. }
  63. }
  64.  
  65. return mav;
  66. }
  67.  
  68. /**
  69. * 获取参数,执行方法前的准备逻辑
  70. * 源码位置:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(HttpServletRequest, HttpServletResponse, HandlerMethod)
  71. */
  72. protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
  73. HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
  74. // 把我们的请求req resp包装成 ServletWebRequest
  75. ServletWebRequest webRequest = new ServletWebRequest(request, response);
  76. try {
  77. // 获取容器中全局配置的InitBinder和当前HandlerMethod所对应的Controller中
  78. // 配置的InitBinder,用于进行参数的绑定
  79. WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
  80.  
  81. // 获取容器中全局配置的ModelAttribute和当前HandlerMethod所对应的Controller 中配置的ModelAttribute,
  82. // 这些配置的方法将会在目标方法调用之前进行调用
  83. ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
  84.  
  85. // 封装handlerMethod,会在调用前解析参数、调用后对返回值进行处理
  86. ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
  87. if (this.argumentResolvers != null) {
  88. // 让invocableMethod拥有参数解析能力
  89. invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
  90. }
  91. if (this.returnValueHandlers != null) {
  92. // 让invocableMethod拥有返回值处理能力
  93. invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
  94. }
  95. // 让invocableMethod拥有InitBinder解析能力
  96. invocableMethod.setDataBinderFactory(binderFactory);
  97. // 设置ParameterNameDiscoverer,该对象将按照一定的规则获取当前参数的名称
  98. invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
  99. // ModelAndView处理容器
  100. ModelAndViewContainer mavContainer = new ModelAndViewContainer();
  101. // 将request的Attribute复制一份到ModelMap
  102. mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
  103. // *调用我们标注了@ModelAttribute的方法,主要是为我们的目标方法预加载
  104. modelFactory.initModel(webRequest, mavContainer, invocableMethod);
  105. // 重定向的时候,忽略model中的数据 默认false
  106. mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
  107.  
  108. // 获取当前的AsyncWebRequest,这里AsyncWebRequest的主要作用是用于判断目标
  109. // handler的返回值是否为WebAsyncTask或DeferredResult,如果是这两种中的一种,
  110. // 则说明当前请求的处理应该是异步的。所谓的异步,指的是当前请求会将Controller中
  111. // 封装的业务逻辑放到一个线程池中进行调用,待该调用有返回结果之后再返回到response中。
  112. // 这种处理的优点在于用于请求分发的线程能够解放出来,从而处理更多的请求,提高吞吐。
  113. // 只有待目标任务完成之后才会回来将该异步任务的结果返回。
  114. AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
  115. asyncWebRequest.setTimeout(this.asyncRequestTimeout);
  116. // 封装异步任务的线程池、request、interceptors到WebAsyncManager中
  117. WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
  118. asyncManager.setTaskExecutor(this.taskExecutor);
  119. asyncManager.setAsyncWebRequest(asyncWebRequest);
  120. asyncManager.registerCallableInterceptors(this.callableInterceptors);
  121. asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
  122.  
  123. // 这里就是用于判断当前请求是否有异步任务结果的,如果存在,则对异步任务结果进行封装
  124. if (asyncManager.hasConcurrentResult()) {
  125. Object result = asyncManager.getConcurrentResult();
  126. mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
  127. asyncManager.clearConcurrentResult();
  128. LogFormatUtils.traceDebug(logger, traceOn -> {
  129. String formatted = LogFormatUtils.formatValue(result, !traceOn);
  130. return "Resume with async result [" + formatted + "]";
  131. });
  132. invocableMethod = invocableMethod.wrapConcurrentResult(result);
  133. }
  134. // *对请求参数进行处理,调用目标HandlerMethod,并且将返回值封装为一个ModelAndView对象
  135. invocableMethod.invokeAndHandle(webRequest, mavContainer);
  136. if (asyncManager.isConcurrentHandlingStarted()) {
  137. return null;
  138. }
  139.  
  140. // 对封装的ModelAndView进行处理,主要是判断当前请求是否进行了重定向,如果进行了重定向,
  141. // 还会判断是否需要将FlashAttributes封装到新的请求中
  142. return getModelAndView(mavContainer, modelFactory, webRequest);
  143. }
  144. finally {
  145. webRequest.requestCompleted();
  146. }
  147. }
  148.  
  149. /**
  150. * 获取参数,执行方法
  151. * 源码位置:org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletWebRequest, ModelAndViewContainer, Object...)
  152. */
  153. public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
  154. Object... providedArgs) throws Exception {
  155.  
  156. /*真正的调用我们的目标对象 很重要 很重要*/
  157. Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
  158. // 设置相关的返回状态
  159. setResponseStatus(webRequest);
  160. // 如果请求处理完成,则设置requestHandled属性
  161. if (returnValue == null) {
  162. if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
  163. disableContentCachingIfNecessary(webRequest);
  164. mavContainer.setRequestHandled(true);
  165. return;
  166. }
  167. }
  168. // 如果请求失败,但是有错误原因,那么也会设置requestHandled属性
  169. else if (StringUtils.hasText(getResponseStatusReason())) {
  170. mavContainer.setRequestHandled(true);
  171. return;
  172. }
  173.  
  174. mavContainer.setRequestHandled(false);
  175. Assert.state(this.returnValueHandlers != null, "No return value handlers");
  176. try {
  177. // 遍历当前容器中所有ReturnValueHandler,判断哪种handler支持当前返回值的处理,
  178. // 如果支持,则使用该handler处理该返回值
  179. this.returnValueHandlers.handleReturnValue(
  180. returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
  181. }
  182. catch (Exception ex) {
  183. if (logger.isTraceEnabled()) {
  184. logger.trace(formatErrorForReturnValue(returnValue), ex);
  185. }
  186. throw ex;
  187. }
  188. }

七、渲染视图逻辑

  1. /**
  2. * 渲染视图逻辑
  3. * 源码位置:org.springframework.web.servlet.DispatcherServlet.processDispatchResult(HttpServletRequest, HttpServletResponse, HandlerExecutionChain, ModelAndView, Exception)
  4. */
  5. private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
  6. @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
  7. @Nullable Exception exception) throws Exception {
  8.  
  9. boolean errorView = false;
  10.  
  11. // 异常视图
  12. if (exception != null) {
  13. if (exception instanceof ModelAndViewDefiningException) {
  14. logger.debug("ModelAndViewDefiningException encountered", exception);
  15. mv = ((ModelAndViewDefiningException) exception).getModelAndView();
  16. }
  17. else {
  18. Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
  19. mv = processHandlerException(request, response, handler, exception);
  20. errorView = (mv != null);
  21. }
  22. }
  23.  
  24. // Did the handler return a view to render?
  25. if (mv != null && !mv.wasCleared()) {
  26. // 解析、渲染视图:解析视图名,拼接前后缀
  27. render(mv, request, response);
  28. if (errorView) {
  29. WebUtils.clearErrorRequestAttributes(request);
  30. }
  31. }
  32. else {
  33. if (logger.isTraceEnabled()) {
  34. logger.trace("No view rendering, null ModelAndView returned.");
  35. }
  36. }
  37.  
  38. if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
  39. // Concurrent handling started during a forward
  40. return;
  41. }
  42.  
  43. if (mappedHandler != null) {
  44. // Exception (if any) is already handled.. 拦截器:AfterCompletion
  45. mappedHandler.triggerAfterCompletion(request, response, null);
  46. }
  47. }

到此这篇关于Java spring mvc请求详情介绍的文章就介绍到这了,更多相关spring mvc请求内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号