当前位置:   article > 正文

SpringMVC源码学习笔记之请求处理流程_如何处理mvc web请求讨论的步骤

如何处理mvc web请求讨论的步骤

一、常用组件

1、DispatcherServlet

前端控制器,SpringMVC里最核心的组件,是整个SpringMVC请求流程的中心,主要流程都是由DispatcherServlet来调用其他组件,而且看名字就知道,它是一个Servlet

2、HandlerMapping

处理器映射器,根据请求来查找对应的处理器Handler,其实就是Controller

3、Handler(Controller)

处理器,由软件工程师开发,其实就是Controller,用于具体处理用户的请求

4、HandlerAdapter

处理器适配器,因为SpringMVC中的Handler可以是任意的形式,只要能处理请求就可以了,但是Servlet需要的处理方法的结构却是固定的,都是以request和response为参数的方法,所以如何让固定的Servlet处理方法调用灵活的Handler来进行处理呢?这就要用到HandlerAdapter了

注:网上看到一个很有意思的形容:

Handler是用来干活的工具

HandlerMapping用来根据需要干的活找到对应的工具

HandlerAdapter是使用工具干活的人

5、ViewResolver

视图解析器,根据视图名称解析成View类型的视图,View是用来渲染页面的,也就是将程序返回的数据填入模板里,生成html或者其他类型的文件,具体使用哪个模板,用什么规则填入数据就是ViewResolver要做的事,然后具体的渲染交给View去做

二、流程图

流程梳理:

1、用户通过浏览器发送请求到前端控制器(DispatcherServlet)

2、前端控制器(DispatcherServlet)将用户请求交给处理器映射器(HandlerMapping)

3-4、处理器映射器(HandlerMapping)找到负责这个请求的处理器(Handler)并和拦截器链一起封装成处理器执行链(HandlerExecutionChain)交给前端控制器(DispatcherServlet)

5、前端控制器(DispatcherServlet)会根据处理器(Handler)找到对应的处理器适配器(HandlerAdaptor)

6-9、处理器适配器(HandlerAdaptor) 会去执行具体的Controller,Controller将处理结果及要跳转的视图封装到ModelAndView返回给处理器适配器(HandlerAdaptor),并在执行Controller前后调用拦截器链

10、处理器适配器(HandlerAdaptor) 将ModelAndView返回给前端控制器(DispatcherServlet)

11、前端控制器(DispatcherServlet)将ModelAndView交给视图解析器(ViewResolver)

12、视图解析器(ViewResolver)将ModelAndView解析为具体的视图(View)返回给前端控制器(DispatcherServlet)

13、前端控制器(DispatcherServlet)调用视图对象,让其自己 (View) 进行渲染(将模型数据填充至视图中) ,形成响应 (HttpResponse)

14、前端控制器(DispatcherServlet)将响应 (HttpResponse) 返回给浏览器

三、源码解读

1、doDispatch

首先我们要先知道SpringMVC的Servlet分为三层HttpServletBean、FrameworkServlet和DispatcherServlet,我们知道Servlet的入口是service方法,FrameworkServlet重写了service方法,我们往里跟代码,最终会来到DispatcherServlet的核心方法doDispatch

  1. //DispatcherServlet
  2. protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
  3. HttpServletRequest processedRequest = request;
  4. HandlerExecutionChain mappedHandler = null;
  5. boolean multipartRequestParsed = false;
  6. WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
  7. try {
  8. ModelAndView mv = null;
  9. Exception dispatchException = null;
  10. try {
  11. //检查是否是文件上传的请求
  12. processedRequest = checkMultipart(request);
  13. multipartRequestParsed = (processedRequest != request);
  14. //获取处理器,注意这里的mappedHandler里包含了handler和拦截器链
  15. mappedHandler = getHandler(processedRequest);
  16. if (mappedHandler == null) {
  17. //找不到处理器,报404
  18. noHandlerFound(processedRequest, response);
  19. return;
  20. }
  21. //根据处理器里的handler获取对应的适配器
  22. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
  23. //处理last-modified请求头
  24. String method = request.getMethod();
  25. boolean isGet = "GET".equals(method);
  26. if (isGet || "HEAD".equals(method)) {
  27. long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
  28. if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
  29. return;
  30. }
  31. }
  32. //在处理请求前先执行拦截器的preHandle方法,这个方法会返回一个boolean类型的值
  33. //如果是true,就交给后面的拦截器继续处理,
  34. //如果是false就表示处理完了,顺便也把response搞定
  35. if (!mappedHandler.applyPreHandle(processedRequest, response)) {
  36. return;
  37. }
  38. //用适配器处理请求,返回ModelAndView
  39. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
  40. if (asyncManager.isConcurrentHandlingStarted()) {
  41. return;
  42. }
  43. //判断是否需要viewNameTranslator从request里获取view的名字
  44. applyDefaultViewName(processedRequest, mv);
  45. //执行拦截器的PostHandle方法
  46. mappedHandler.applyPostHandle(processedRequest, response, mv);
  47. }
  48. catch (Exception ex) {
  49. dispatchException = ex;
  50. }
  51. catch (Throwable err) {
  52. dispatchException = new NestedServletException("Handler dispatch failed", err);
  53. }
  54. //页面渲染,调用拦截器的afterCompletion方法等
  55. processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
  56. }
  57. catch (Exception ex) {
  58. triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
  59. }
  60. catch (Throwable err) {
  61. triggerAfterCompletion(processedRequest, response, mappedHandler,
  62. new NestedServletException("Handler processing failed", err));
  63. }
  64. finally {
  65. if (asyncManager.isConcurrentHandlingStarted()) {
  66. if (mappedHandler != null) {
  67. mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
  68. }
  69. }
  70. else {
  71. if (multipartRequestParsed) {
  72. cleanupMultipart(processedRequest);
  73. }
  74. }
  75. }
  76. }

2、getHandler

  1. //获取处理器,注意这里的mappedHandler里包含了handler和拦截器链
  2. mappedHandler = getHandler(processedRequest);

首先我们看下18行的getHandler方法,对应流程图中的2-4步

  1. //DispatcherServlet
  2. @Nullable
  3. protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  4. if (this.handlerMappings != null) {
  5. for (HandlerMapping mapping : this.handlerMappings) {
  6. //逐个使用HandlerMapping去获取Handler,如果获取到了就返回,没获取到就换下一个
  7. HandlerExecutionChain handler = mapping.getHandler(request);
  8. if (handler != null) {
  9. return handler;
  10. }
  11. }
  12. }
  13. return null;
  14. }

这里的handlerMappings是个List集合,HandlerMapper有很多实现类,最重要的就是RequestMappingHandlerMapping和BeanNameUrlHandlerMapping,我们记住这两个类,继续看第7行getHandler,进入到AbstractHandlerMapping类里

  1. //AbstractHandlerMapping
  2. @Override
  3. @Nullable
  4. public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  5. //获取handler
  6. Object handler = getHandlerInternal(request);
  7. if (handler == null) {
  8. handler = getDefaultHandler();
  9. }
  10. if (handler == null) {
  11. return null;
  12. }
  13. if (handler instanceof String) {
  14. String handlerName = (String) handler;
  15. handler = obtainApplicationContext().getBean(handlerName);
  16. }
  17. //找到匹配的拦截器和handler一起封装成一个HandlerExecutionChain
  18. HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
  19. if (logger.isTraceEnabled()) {
  20. logger.trace("Mapped to " + handler);
  21. }
  22. else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
  23. logger.debug("Mapped to " + executionChain.getHandler());
  24. }
  25. if (CorsUtils.isCorsRequest(request)) {
  26. CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
  27. CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
  28. CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
  29. executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
  30. }
  31. return executionChain;
  32. }

核心逻辑是第6行的getHandlerInternal,getHandlerInternal是个模板方法,最终会调用子类实现,这里有两个重要的实现类,分别是AbstractHandlerMethodMapping和AbstractUrlHandlerMapping,上面我们提到HandlerMapper有两个非常主要的实现类:RequestMappingHandlerMapping和BeanNameUrlHandlerMapping,我们看看这两个类的类图

我们发现RequestMappingHandlerMapping是AbstractHandlerMethodMapping的子类,而BeanNameUrlHandlerMapping是AbstractUrlHandlerMapping的子类

  • RequestMappingHandlerMapping:主要用来存储RequestMapping注解相关的控制器和url的映射关系

  • BeanNameUrlHandlerMapping: 主要用来处理Bean name直接以 / 开头的控制器和url的映射关系。

我们最常用的其实还是RequestMappingHandlerMapping,所以我们进入AbstractHandlerMethodMapping的getHandlerInternal方法,继续看

  1. //AbstractHandlerMethodMapping
  2. @Override
  3. protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
  4. //获取requestMapping地址
  5. String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
  6. this.mappingRegistry.acquireReadLock();
  7. try {
  8. //查找Handler
  9. HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
  10. return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
  11. }
  12. finally {
  13. this.mappingRegistry.releaseReadLock();
  14. }
  15. }

第9行核心方法进去

  1. //AbstractHandlerMethodMapping
  2. @Nullable
  3. protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
  4. List<Match> matches = new ArrayList<>();
  5. //从mappingRegistry中获取命中的方法
  6. List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
  7. if (directPathMatches != null) {
  8. //寻找合适的mapping,根据属性去精确查找,最终防到matches中
  9. addMatchingMappings(directPathMatches, matches, request);
  10. }
  11. if (matches.isEmpty()) {
  12. // No choice but to go through all mappings...
  13. addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
  14. }
  15. if (!matches.isEmpty()) {
  16. Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
  17. matches.sort(comparator);
  18. Match bestMatch = matches.get(0);
  19. if (matches.size() > 1) {
  20. if (logger.isTraceEnabled()) {
  21. logger.trace(matches.size() + " matching mappings: " + matches);
  22. }
  23. if (CorsUtils.isPreFlightRequest(request)) {
  24. return PREFLIGHT_AMBIGUOUS_MATCH;
  25. }
  26. Match secondBestMatch = matches.get(1);
  27. if (comparator.compare(bestMatch, secondBestMatch) == 0) {
  28. Method m1 = bestMatch.handlerMethod.getMethod();
  29. Method m2 = secondBestMatch.handlerMethod.getMethod();
  30. String uri = request.getRequestURI();
  31. throw new IllegalStateException(
  32. "Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
  33. }
  34. }
  35. request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
  36. handleMatch(bestMatch.mapping, lookupPath, request);
  37. return bestMatch.handlerMethod;
  38. }
  39. else {
  40. return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
  41. }
  42. }

具体看下第9行addMatchingMappings

  1. private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
  2. for (T mapping : mappings) {
  3. T match = getMatchingMapping(mapping, request);
  4. if (match != null) {
  5. matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
  6. }
  7. }
  8. }

这里有个mappingRegistry很重要,mappingRegistry.getMappings,返回的是HandlerMethod的map,这一步相当于把匹配到的HandlerMethod封装到Match对象中,最后加到matches集合里,最后排序,取出第一个匹配的Handler返回

我们回到getHandler方法

  1. //AbstractHandlerMapping
  2. @Override
  3. @Nullable
  4. public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  5. //获取handler
  6. Object handler = getHandlerInternal(request);
  7. if (handler == null) {
  8. handler = getDefaultHandler();
  9. }
  10. if (handler == null) {
  11. return null;
  12. }
  13. if (handler instanceof String) {
  14. String handlerName = (String) handler;
  15. handler = obtainApplicationContext().getBean(handlerName);
  16. }
  17. //找到匹配的拦截器和handler一起封装成一个HandlerExecutionChain
  18. HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
  19. if (logger.isTraceEnabled()) {
  20. logger.trace("Mapped to " + handler);
  21. }
  22. else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
  23. logger.debug("Mapped to " + executionChain.getHandler());
  24. }
  25. if (CorsUtils.isCorsRequest(request)) {
  26. CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
  27. CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
  28. CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
  29. executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
  30. }
  31. return executionChain;
  32. }

第6行返回的就是刚才的HandlerMethod对象,然后调用getHandlerExecutionChain方法,将HandlerMethod和拦截器链封装成HandlerExecutionChain对象返回

3、HandlerAdapter.handle

  1. //用适配器处理请求,返回ModelAndView
  2. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

下面看第47行handle方法,点击进到实现类AbstractHandlerMethodAdapter的handle方法中

  1. @Override
  2. @Nullable
  3. public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
  4. throws Exception {
  5. return handleInternal(request, response, (HandlerMethod) handler);
  6. }

继续点击handleInternal进入子类RequestMappingHandlerAdapter的handleInternal方法中

  1. //RequestMappingHandlerAdapter
  2. @Override
  3. protected ModelAndView handleInternal(HttpServletRequest request,
  4. HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
  5. ModelAndView mav;
  6. //检查是否支持当前request的请求方式和session
  7. checkRequest(request);
  8. //如果需要,在同步块中执行invokeHandlerMethod。
  9. if (this.synchronizeOnSession) {
  10. HttpSession session = request.getSession(false);
  11. if (session != null) {
  12. Object mutex = WebUtils.getSessionMutex(session);
  13. synchronized (mutex) {
  14. mav = invokeHandlerMethod(request, response, handlerMethod);
  15. }
  16. }
  17. else {
  18. //无HttpSession可用->无需互斥
  19. mav = invokeHandlerMethod(request, response, handlerMethod);
  20. }
  21. }
  22. else {
  23. //不需要同步会话
  24. mav = invokeHandlerMethod(request, response, handlerMethod);
  25. }
  26. if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
  27. if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
  28. applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
  29. }
  30. else {
  31. prepareResponse(response);
  32. }
  33. }
  34. return mav;
  35. }

最终会调用invokeHandlerMethod方法,点击进去

  1. //RequestMappingHandlerAdapter
  2. @Nullable
  3. protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
  4. HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
  5. ServletWebRequest webRequest = new ServletWebRequest(request, response);
  6. try {
  7. //省略...
  8. invocableMethod.invokeAndHandle(webRequest, mavContainer);
  9. if (asyncManager.isConcurrentHandlingStarted()) {
  10. return null;
  11. }
  12. return getModelAndView(mavContainer, modelFactory, webRequest);
  13. }
  14. finally {
  15. webRequest.requestCompleted();
  16. }
  17. }

继续点击10行invokeAndHandle进到类ServletInvocableHandlerMethod中

  1. public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
  2. Object... providedArgs) throws Exception {
  3. //重点
  4. Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
  5. setResponseStatus(webRequest);
  6. if (returnValue == null) {
  7. if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
  8. mavContainer.setRequestHandled(true);
  9. return;
  10. }
  11. }
  12. else if (StringUtils.hasText(getResponseStatusReason())) {
  13. mavContainer.setRequestHandled(true);
  14. return;
  15. }
  16. mavContainer.setRequestHandled(false);
  17. Assert.state(this.returnValueHandlers != null, "No return value handlers");
  18. try {
  19. this.returnValueHandlers.handleReturnValue(
  20. returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
  21. }
  22. catch (Exception ex) {
  23. if (logger.isTraceEnabled()) {
  24. logger.trace(formatErrorForReturnValue(returnValue), ex);
  25. }
  26. throw ex;
  27. }
  28. }

点击5行invokeForRequest进入其父类InvocableHandlerMethod中

  1. @Nullable
  2. public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
  3. Object... providedArgs) throws Exception {
  4. //获取方法参数
  5. Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
  6. if (logger.isTraceEnabled()) {
  7. logger.trace("Arguments: " + Arrays.toString(args));
  8. }
  9. //执行具体业务
  10. return doInvoke(args);
  11. }

其中doInvoke方法最终会通过反射调用到Controller上的方法,我们具体看看getMethodArgumentValues方法

  1. protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
  2. Object... providedArgs) throws Exception {
  3. //获取Controller对应的方法所有参数,该部分在程序启动时就已经解析好了
  4. if (ObjectUtils.isEmpty(getMethodParameters())) {
  5. return EMPTY_ARGS;
  6. }
  7. MethodParameter[] parameters = getMethodParameters();
  8. Object[] args = new Object[parameters.length];
  9. //遍历所有参数,进行赋值
  10. for (int i = 0; i < parameters.length; i++) {
  11. MethodParameter parameter = parameters[i];
  12. parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
  13. args[i] = findProvidedArgument(parameter, providedArgs);
  14. if (args[i] != null) {
  15. continue;
  16. }
  17. if (!this.resolvers.supportsParameter(parameter)) {
  18. throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
  19. }
  20. try {
  21. //解析参数并赋值,这里会根据参数找到对应的解析器进行解析
  22. args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
  23. }
  24. catch (Exception ex) {
  25. if (logger.isDebugEnabled()) {
  26. String error = ex.getMessage();
  27. if (error != null && !error.contains(parameter.getExecutable().toGenericString())) {
  28. logger.debug(formatArgumentError(parameter, error));
  29. }
  30. }
  31. throw ex;
  32. }
  33. }
  34. return args;
  35. }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小惠珠哦/article/detail/1015675
推荐阅读
相关标签
  

闽ICP备14008679号