相信spring-mvc这种被玩坏了的架构理念,大家都烂熟于胸了,不过还是想来扒一扒他的细节。

  一个http请求,怎么样被 spring 接收,又怎样做出响应呢?

一般地,我们会配置一个 web.xml,然后开始代码之旅。

   在 web.xml 中配置 servlet-mapping, 将请求转发到 DispatcherServlet, 那么我们认为 DispatcherServlet 是我们的第一棒交接者!

  1. <servlet>
  2. <servlet-name>springMVC</servlet-name>
  3. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  4. <init-param>
  5. <param-name>contextConfigLocation</param-name>
  6. <param-value>classpath:applicationContext.xml</param-value>
  7. </init-param>
  8. <load-on-startup>1</load-on-startup>
  9. </servlet>
  10.  
  11. <servlet-mapping>
  12. <servlet-name>springMVC</servlet-name>
  13. <url-pattern>/</url-pattern>
  14. </servlet-mapping>

// tomcat 接到http请求后,会主动创建一个servlet, 然后调用进应用代码中, 创建的代码如下

  1. // Allocate a servlet instance to process this request
  2. try {
  3. if (!unavailable) {
  4. servlet = wrapper.allocate();
  5. }
  6. } catch (ServletException e) {
  7. wrapper.getLogger().error(sm.getString("applicationDispatcher.allocateException",
  8. wrapper.getName()), StandardWrapper.getRootCause(e));
  9. servletException = e;
  10. } catch (Throwable e) {
  11. ExceptionUtils.handleThrowable(e);
  12. wrapper.getLogger().error(sm.getString("applicationDispatcher.allocateException",
  13. wrapper.getName()), e);
  14. servletException = new ServletException
  15. (sm.getString("applicationDispatcher.allocateException",
  16. wrapper.getName()), e);
  17. servlet = null;
  18. }

// org.apache.catalina.core.StandardWrapper.allocate(), 创建 servlet,

  1. /**
  2. * Allocate an initialized instance of this Servlet that is ready to have
  3. * its <code>service()</code> method called. If the servlet class does
  4. * not implement <code>SingleThreadModel</code>, the (only) initialized
  5. * instance may be returned immediately. If the servlet class implements
  6. * <code>SingleThreadModel</code>, the Wrapper implementation must ensure
  7. * that this instance is not allocated again until it is deallocated by a
  8. * call to <code>deallocate()</code>.
  9. *
  10. * @exception ServletException if the servlet init() method threw
  11. * an exception
  12. * @exception ServletException if a loading error occurs
  13. */
  14. @Override
  15. public Servlet allocate() throws ServletException {
  16.  
  17. // If we are currently unloading this servlet, throw an exception
  18. if (unloading) {
  19. throw new ServletException(sm.getString("standardWrapper.unloading", getName()));
  20. }
  21.  
  22. boolean newInstance = false;
  23.  
  24. // If not SingleThreadedModel, return the same instance every time
  25. if (!singleThreadModel) {
  26. // Load and initialize our instance if necessary
  27. if (instance == null || !instanceInitialized) {
  28. synchronized (this) {
  29. if (instance == null) {
  30. try {
  31. if (log.isDebugEnabled()) {
  32. log.debug("Allocating non-STM instance");
  33. }
  34.  
  35. // Note: We don't know if the Servlet implements
  36. // SingleThreadModel until we have loaded it.
  37. instance = loadServlet();
  38. newInstance = true;
  39. if (!singleThreadModel) {
  40. // For non-STM, increment here to prevent a race
  41. // condition with unload. Bug 43683, test case
  42. // #3
  43. countAllocated.incrementAndGet();
  44. }
  45. } catch (ServletException e) {
  46. throw e;
  47. } catch (Throwable e) {
  48. ExceptionUtils.handleThrowable(e);
  49. throw new ServletException(sm.getString("standardWrapper.allocate"), e);
  50. }
  51. }
  52. if (!instanceInitialized) {
  53. initServlet(instance);
  54. }
  55. }
  56. }
  57.  
  58. if (singleThreadModel) {
  59. if (newInstance) {
  60. // Have to do this outside of the sync above to prevent a
  61. // possible deadlock
  62. synchronized (instancePool) {
  63. instancePool.push(instance);
  64. nInstances++;
  65. }
  66. }
  67. } else {
  68. if (log.isTraceEnabled()) {
  69. log.trace(" Returning non-STM instance");
  70. }
  71. // For new instances, count will have been incremented at the
  72. // time of creation
  73. if (!newInstance) {
  74. countAllocated.incrementAndGet();
  75. }
  76. return instance;
  77. }
  78. }
  79.  
  80. synchronized (instancePool) {
  81. while (countAllocated.get() >= nInstances) {
  82. // Allocate a new instance if possible, or else wait
  83. if (nInstances < maxInstances) {
  84. try {
  85. instancePool.push(loadServlet());
  86. nInstances++;
  87. } catch (ServletException e) {
  88. throw e;
  89. } catch (Throwable e) {
  90. ExceptionUtils.handleThrowable(e);
  91. throw new ServletException(sm.getString("standardWrapper.allocate"), e);
  92. }
  93. } else {
  94. try {
  95. instancePool.wait();
  96. } catch (InterruptedException e) {
  97. // Ignore
  98. }
  99. }
  100. }
  101. if (log.isTraceEnabled()) {
  102. log.trace(" Returning allocated STM instance");
  103. }
  104. countAllocated.incrementAndGet();
  105. return instancePool.pop();
  106. }
  107. }

// 最后,会先调用 filter, 完成之后再调用 servlet.service()

  1. private void internalDoFilter(ServletRequest request,
  2. ServletResponse response)
  3. throws IOException, ServletException {
  4.  
  5. // Call the next filter if there is one
  6. if (pos < n) {
  7. ApplicationFilterConfig filterConfig = filters[pos++];
  8. try {
  9. Filter filter = filterConfig.getFilter();
  10.  
  11. if (request.isAsyncSupported() && "false".equalsIgnoreCase(
  12. filterConfig.getFilterDef().getAsyncSupported())) {
  13. request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
  14. }
  15. if( Globals.IS_SECURITY_ENABLED ) {
  16. final ServletRequest req = request;
  17. final ServletResponse res = response;
  18. Principal principal =
  19. ((HttpServletRequest) req).getUserPrincipal();
  20.  
  21. Object[] args = new Object[]{req, res, this};
  22. SecurityUtil.doAsPrivilege ("doFilter", filter, classType, args, principal);
  23. } else {
  24. filter.doFilter(request, response, this);
  25. }
  26. } catch (IOException | ServletException | RuntimeException e) {
  27. throw e;
  28. } catch (Throwable e) {
  29. e = ExceptionUtils.unwrapInvocationTargetException(e);
  30. ExceptionUtils.handleThrowable(e);
  31. throw new ServletException(sm.getString("filterChain.filter"), e);
  32. }
  33. return;
  34. }
  35.  
  36. // We fell off the end of the chain -- call the servlet instance
  37. try {
  38. if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
  39. lastServicedRequest.set(request);
  40. lastServicedResponse.set(response);
  41. }
  42.  
  43. if (request.isAsyncSupported() && !servletSupportsAsync) {
  44. request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
  45. Boolean.FALSE);
  46. }
  47. // Use potentially wrapped request from this point
  48. if ((request instanceof HttpServletRequest) &&
  49. (response instanceof HttpServletResponse) &&
  50. Globals.IS_SECURITY_ENABLED ) {
  51. final ServletRequest req = request;
  52. final ServletResponse res = response;
  53. Principal principal =
  54. ((HttpServletRequest) req).getUserPrincipal();
  55. Object[] args = new Object[]{req, res};
  56. SecurityUtil.doAsPrivilege("service",
  57. servlet,
  58. classTypeUsedInService,
  59. args,
  60. principal);
  61. } else {
  62. servlet.service(request, response);
  63. }
  64. } catch (IOException | ServletException | RuntimeException e) {
  65. throw e;
  66. } catch (Throwable e) {
  67. e = ExceptionUtils.unwrapInvocationTargetException(e);
  68. ExceptionUtils.handleThrowable(e);
  69. throw new ServletException(sm.getString("filterChain.servlet"), e);
  70. } finally {
  71. if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
  72. lastServicedRequest.set(null);
  73. lastServicedResponse.set(null);
  74. }
  75. }
  76. }

// 现在,到了 DispatcherServlet 出场了,由 DispatcherServlet 的父类 org.springframework.web.servlet.FrameworkServlet.service()接力, 开始处理

  1. /**
  2. * Override the parent class implementation in order to intercept PATCH requests.
  3. */
  4. @Override
  5. protected void service(HttpServletRequest request, HttpServletResponse response)
  6. throws ServletException, IOException {
  7.  
  8. HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
  9. if (HttpMethod.PATCH == httpMethod || httpMethod == null) {
  10. processRequest(request, response);
  11. }
  12. else {
  13. // 交由 HttpServlet.service() 处理,转发 doGet,doPost 等等方法
  14. super.service(request, response);
  15. }
  16. }
  17.  
  18. // 父类 HttpServlet.service(), 只负责转发请求,由子类进行相应处理
  19. protected void service(HttpServletRequest req, HttpServletResponse resp)
  20. throws ServletException, IOException
  21. {
  22. String method = req.getMethod();
  23.  
  24. if (method.equals(METHOD_GET)) {
  25. long lastModified = getLastModified(req);
  26. if (lastModified == -1) {
  27. // servlet doesn't support if-modified-since, no reason
  28. // to go through further expensive logic
  29. doGet(req, resp);
  30. } else {
  31. long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
  32. if (ifModifiedSince < lastModified) {
  33. // If the servlet mod time is later, call doGet()
  34. // Round down to the nearest second for a proper compare
  35. // A ifModifiedSince of -1 will always be less
  36. maybeSetLastModified(resp, lastModified);
  37. doGet(req, resp);
  38. } else {
  39. resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
  40. }
  41. }
  42.  
  43. } else if (method.equals(METHOD_HEAD)) {
  44. long lastModified = getLastModified(req);
  45. maybeSetLastModified(resp, lastModified);
  46. doHead(req, resp);
  47.  
  48. } else if (method.equals(METHOD_POST)) {
  49. doPost(req, resp);
  50.  
  51. } else if (method.equals(METHOD_PUT)) {
  52. doPut(req, resp);
  53.  
  54. } else if (method.equals(METHOD_DELETE)) {
  55. doDelete(req, resp);
  56.  
  57. } else if (method.equals(METHOD_OPTIONS)) {
  58. doOptions(req,resp);
  59.  
  60. } else if (method.equals(METHOD_TRACE)) {
  61. doTrace(req,resp);
  62.  
  63. } else {
  64. //
  65. // Note that this means NO servlet supports whatever
  66. // method was requested, anywhere on this server.
  67. //
  68.  
  69. String errMsg = lStrings.getString("http.method_not_implemented");
  70. Object[] errArgs = new Object[1];
  71. errArgs[0] = method;
  72. errMsg = MessageFormat.format(errMsg, errArgs);
  73.  
  74. resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
  75. }
  76. }

// 比如 FrameworkServlet.doGet()/doXXX() 方法重写, 调用 processRequest()

  1. /**
  2. * Delegate GET requests to processRequest/doService.
  3. * <p>Will also be invoked by HttpServlet's default implementation of {@code doHead},
  4. * with a {@code NoBodyResponse} that just captures the content length.
  5. * @see #doService
  6. * @see #doHead
  7. */
  8. @Override
  9. protected final void doGet(HttpServletRequest request, HttpServletResponse response)
  10. throws ServletException, IOException {
  11.  
  12. processRequest(request, response);
  13. }

// FrameworkServlet.processRequest() 做一些全局设置,然后交由 doService() 进行具体处理, doService() 由子类实现,也即 DispatcherServlet.doService()

  1. protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
  2. throws ServletException, IOException {
  3.  
  4. long startTime = System.currentTimeMillis();
  5. Throwable failureCause = null;
  6.  
  7. LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
  8. LocaleContext localeContext = buildLocaleContext(request);
  9.  
  10. RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
  11. ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
  12.  
  13. WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
  14. asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
  15.  
  16. initContextHolders(request, localeContext, requestAttributes);
  17.  
  18. try {
  19. // 具体处理,交由 DispatcherServlet 处理
  20. doService(request, response);
  21. }
  22. catch (ServletException ex) {
  23. failureCause = ex;
  24. throw ex;
  25. }
  26. catch (IOException ex) {
  27. failureCause = ex;
  28. throw ex;
  29. }
  30. catch (Throwable ex) {
  31. failureCause = ex;
  32. throw new NestedServletException("Request processing failed", ex);
  33. }
  34.  
  35. finally {
  36. resetContextHolders(request, previousLocaleContext, previousAttributes);
  37. if (requestAttributes != null) {
  38. // 请求完成回调
  39. requestAttributes.requestCompleted();
  40. }
  41.  
  42. if (logger.isDebugEnabled()) {
  43. if (failureCause != null) {
  44. this.logger.debug("Could not complete request", failureCause);
  45. }
  46. else {
  47. if (asyncManager.isConcurrentHandlingStarted()) {
  48. logger.debug("Leaving response open for concurrent processing");
  49. }
  50. else {
  51. this.logger.debug("Successfully completed request");
  52. }
  53. }
  54. }
  55.  
  56. // 发布完成事件
  57. publishRequestHandledEvent(request, response, startTime, failureCause);
  58. }
  59. }

// locale 上下文管理

  1. private void initContextHolders(
  2. HttpServletRequest request, LocaleContext localeContext, RequestAttributes requestAttributes) {
  3.  
  4. // private static final ThreadLocal<LocaleContext> localeContextHolder = new NamedThreadLocal<LocaleContext>("LocaleContext");
  5. if (localeContext != null) {
  6. LocaleContextHolder.setLocaleContext(localeContext, this.threadContextInheritable);
  7. }
  8. // private static final ThreadLocal<RequestAttributes> requestAttributesHolder = new NamedThreadLocal<RequestAttributes>("Request attributes");
  9. if (requestAttributes != null) {
  10. RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
  11. }
  12. if (logger.isTraceEnabled()) {
  13. logger.trace("Bound request context to thread: " + request);
  14. }
  15. }

// org.springframework.web.servlet.DispatcherServlet, 进行具体请求转发

  1. /**
  2. * Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}
  3. * for the actual dispatching.
  4. */
  5. @Override
  6. protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
  7. if (logger.isDebugEnabled()) {
  8. String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
  9. logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
  10. " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
  11. }
  12.  
  13. // Keep a snapshot of the request attributes in case of an include,
  14. // to be able to restore the original attributes after the include.
  15. Map<String, Object> attributesSnapshot = null;
  16. if (WebUtils.isIncludeRequest(request)) {
  17. attributesSnapshot = new HashMap<String, Object>();
  18. Enumeration<?> attrNames = request.getAttributeNames();
  19. while (attrNames.hasMoreElements()) {
  20. String attrName = (String) attrNames.nextElement();
  21. if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
  22. attributesSnapshot.put(attrName, request.getAttribute(attrName));
  23. }
  24. }
  25. }
  26.  
  27. // Make framework objects available to handlers and view objects.
  28. // 设备各种处理器到 request 中
  29. // 上下文管理
  30. request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
  31. // locale 管理
  32. request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
  33. // themeResolver
  34. request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
  35. request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
  36.  
  37. FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
  38. if (inputFlashMap != null) {
  39. request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
  40. }
  41. request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
  42. request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
  43.  
  44. try {
  45. doDispatch(request, response);
  46. }
  47. finally {
  48. if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
  49. // Restore the original attribute snapshot, in case of an include.
  50. if (attributesSnapshot != null) {
  51. restoreAttributesAfterInclude(request, attributesSnapshot);
  52. }
  53. }
  54. }
  55. }

// doDispatch(), 实际分发方法

  1. /**
  2. * Process the actual dispatching to the handler.
  3. * <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
  4. * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
  5. * to find the first that supports the handler class.
  6. * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
  7. * themselves to decide which methods are acceptable.
  8. * @param request current HTTP request
  9. * @param response current HTTP response
  10. * @throws Exception in case of any kind of processing failure
  11. */
  12. protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
  13. HttpServletRequest processedRequest = request;
  14. HandlerExecutionChain mappedHandler = null;
  15. boolean multipartRequestParsed = false;
  16.  
  17. WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
  18.  
  19. try {
  20. ModelAndView mv = null;
  21. Exception dispatchException = null;
  22.  
  23. try {
  24. // 封装 multipart 文件上传,如果是文件上传类,则将其封装为 MultipartHttpServletRequest, 以便后续直接使用
  25. processedRequest = checkMultipart(request);
  26. multipartRequestParsed = (processedRequest != request);
  27.  
  28. // 获取具体uri业务处理器,即 由 RequestMapping 设置的路径
  29. mappedHandler = getHandler(processedRequest);
  30. if (mappedHandler == null || mappedHandler.getHandler() == null) {
  31. // 如果没有找到 handler 则结束处理
  32. noHandlerFound(processedRequest, response);
  33. return;
  34. }
  35.  
  36. // Determine handler adapter for the current request.
  37. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
  38.  
  39. // 对GET|HEAD 进行 last-modified 进行检测
  40. String method = request.getMethod();
  41. boolean isGet = "GET".equals(method);
  42. if (isGet || "HEAD".equals(method)) {
  43. long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
  44. if (logger.isDebugEnabled()) {
  45. logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
  46. }
  47. if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
  48. return;
  49. }
  50. }
  51.  
  52. // 进行处理器前置调用,如果未通过,则结束
  53. if (!mappedHandler.applyPreHandle(processedRequest, response)) {
  54. return;
  55. }
  56.  
  57. // Actually invoke the handler.
  58. // 调用业务处理
  59. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
  60.  
  61. if (asyncManager.isConcurrentHandlingStarted()) {
  62. return;
  63. }
  64.  
  65. // 设置 view
  66. applyDefaultViewName(processedRequest, mv);
  67. // 后置处理
  68. mappedHandler.applyPostHandle(processedRequest, response, mv);
  69. }
  70. catch (Exception ex) {
  71. dispatchException = ex;
  72. }
  73. catch (Throwable err) {
  74. // As of 4.3, we're processing Errors thrown from handler methods as well,
  75. // making them available for @ExceptionHandler methods and other scenarios.
  76. dispatchException = new NestedServletException("Handler dispatch failed", err);
  77. }
  78. // 最后再处理一次结果,如果有必要的话
  79. processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
  80. }
  81. catch (Exception ex) {
  82. triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
  83. }
  84. catch (Throwable err) {
  85. triggerAfterCompletion(processedRequest, response, mappedHandler,
  86. new NestedServletException("Handler processing failed", err));
  87. }
  88. finally {
  89. // 清理环境
  90. if (asyncManager.isConcurrentHandlingStarted()) {
  91. // Instead of postHandle and afterCompletion
  92. if (mappedHandler != null) {
  93. mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
  94. }
  95. }
  96. else {
  97. // Clean up any resources used by a multipart request.
  98. if (multipartRequestParsed) {
  99. cleanupMultipart(processedRequest);
  100. }
  101. }
  102. }
  103. }

// multipart 检测,需设置 multipartResolver, 方能转换,否则直接返回原始请求

  1. /**
  2. * Convert the request into a multipart request, and make multipart resolver available.
  3. * <p>If no multipart resolver is set, simply use the existing request.
  4. * @param request current HTTP request
  5. * @return the processed request (multipart wrapper if necessary)
  6. * @see MultipartResolver#resolveMultipart
  7. */
  8. protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
  9. if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
  10. if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) {
  11. logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, " +
  12. "this typically results from an additional MultipartFilter in web.xml");
  13. }
  14. else if (hasMultipartException(request) ) {
  15. logger.debug("Multipart resolution failed for current request before - " +
  16. "skipping re-resolution for undisturbed error rendering");
  17. }
  18. else {
  19. try {
  20. // 调用 multipartResolver.resolveMultipart(), 由 resolver 进行文件转换处理
  21. return this.multipartResolver.resolveMultipart(request);
  22. }
  23. catch (MultipartException ex) {
  24. if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) != null) {
  25. logger.debug("Multipart resolution failed for error dispatch", ex);
  26. // Keep processing error dispatch with regular request handle below
  27. }
  28. else {
  29. throw ex;
  30. }
  31. }
  32. }
  33. }
  34. // If not returned before: return original request.
  35. return request;
  36. }

// 关键: 获取handler, 以待调用

  1. /**
  2. * Return the HandlerExecutionChain for this request.
  3. * <p>Tries all handler mappings in order.
  4. * @param request current HTTP request
  5. * @return the HandlerExecutionChain, or {@code null} if no handler could be found
  6. */
  7. protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  8. // handlerMappings 中保存了所有可用的路由
  9. for (HandlerMapping hm : this.handlerMappings) {
  10. if (logger.isTraceEnabled()) {
  11. logger.trace(
  12. "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
  13. }
  14. // 由具体的 HandlerMapping 去解析自己的映射
  15. HandlerExecutionChain handler = hm.getHandler(request);
  16. if (handler != null) {
  17. return handler;
  18. }
  19. }
  20. return null;
  21. }
  22.  
  23. // org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
  24. // org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler()
  25. /**
  26. * Look up a handler for the given request, falling back to the default
  27. * handler if no specific one is found.
  28. * @param request current HTTP request
  29. * @return the corresponding handler instance, or the default handler
  30. * @see #getHandlerInternal
  31. */
  32. @Override
  33. public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  34. // 获取 handlerMethod
  35. Object handler = getHandlerInternal(request);
  36. if (handler == null) {
  37. handler = getDefaultHandler();
  38. }
  39. if (handler == null) {
  40. return null;
  41. }
  42. // Bean name or resolved handler?
  43. if (handler instanceof String) {
  44. String handlerName = (String) handler;
  45. handler = getApplicationContext().getBean(handlerName);
  46. }
  47.  
  48. // 获取 handler 链
  49. HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
  50. if (CorsUtils.isCorsRequest(request)) {
  51. CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
  52. CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
  53. CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
  54. executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
  55. }
  56. return executionChain;
  57. }
  58.  
  59. // org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(), 查找 handler
  60. /**
  61. * Look up a handler method for the given request.
  62. */
  63. @Override
  64. protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
  65. // UrlHelper.getLookupPathForRequest() 进行路径分析
  66. String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
  67. if (logger.isDebugEnabled()) {
  68. logger.debug("Looking up handler method for path " + lookupPath);
  69. }
  70. // 加锁读取
  71. this.mappingRegistry.acquireReadLock();
  72. try {
  73. // 根据path查找 handlerMethod
  74. HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
  75. if (logger.isDebugEnabled()) {
  76. if (handlerMethod != null) {
  77. logger.debug("Returning handler method [" + handlerMethod + "]");
  78. }
  79. else {
  80. logger.debug("Did not find handler method for [" + lookupPath + "]");
  81. }
  82. }
  83. // 找到匹配后,将 handler 通过 bean 查找方式包装进 HandlerMethod 中返回
  84. return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
  85. }
  86. finally {
  87. this.mappingRegistry.releaseReadLock();
  88. }
  89. }

// 更细节的查询 handler 动作

  1. // org.springframework.web.util.UrlPathHelper
  2. /**
  3. * Return the mapping lookup path for the given request, within the current
  4. * servlet mapping if applicable, else within the web application.
  5. * <p>Detects include request URL if called within a RequestDispatcher include.
  6. * @param request current HTTP request
  7. * @return the lookup path
  8. * @see #getPathWithinApplication
  9. * @see #getPathWithinServletMapping
  10. */
  11. public String getLookupPathForRequest(HttpServletRequest request) {
  12. // Always use full path within current servlet context?
  13. if (this.alwaysUseFullPath) {
  14. return getPathWithinApplication(request);
  15. }
  16. // Else, use path within current servlet mapping if applicable
  17. String rest = getPathWithinServletMapping(request);
  18. if (!"".equals(rest)) {
  19. return rest;
  20. }
  21. else {
  22. // 返回 /hello/test
  23. return getPathWithinApplication(request);
  24. }
  25. }
  26.  
  27. //
  28. /**
  29. * Return the path within the servlet mapping for the given request,
  30. * i.e. the part of the request's URL beyond the part that called the servlet,
  31. * or "" if the whole URL has been used to identify the servlet.
  32. * <p>Detects include request URL if called within a RequestDispatcher include.
  33. * <p>E.g.: servlet mapping = "/*"; request URI = "/test/a" -> "/test/a".
  34. * <p>E.g.: servlet mapping = "/"; request URI = "/test/a" -> "/test/a".
  35. * <p>E.g.: servlet mapping = "/test/*"; request URI = "/test/a" -> "/a".
  36. * <p>E.g.: servlet mapping = "/test"; request URI = "/test" -> "".
  37. * <p>E.g.: servlet mapping = "/*.test"; request URI = "/a.test" -> "".
  38. * @param request current HTTP request
  39. * @return the path within the servlet mapping, or ""
  40. */
  41. public String getPathWithinServletMapping(HttpServletRequest request) {
  42. String pathWithinApp = getPathWithinApplication(request);
  43. String servletPath = getServletPath(request);
  44. String sanitizedPathWithinApp = getSanitizedPath(pathWithinApp);
  45. String path;
  46.  
  47. // If the app container sanitized the servletPath, check against the sanitized version
  48. if (servletPath.contains(sanitizedPathWithinApp)) {
  49. path = getRemainingPath(sanitizedPathWithinApp, servletPath, false);
  50. }
  51. else {
  52. path = getRemainingPath(pathWithinApp, servletPath, false);
  53. }
  54.  
  55. if (path != null) {
  56. // Normal case: URI contains servlet path.
  57. return path;
  58. }
  59. else {
  60. // Special case: URI is different from servlet path.
  61. String pathInfo = request.getPathInfo();
  62. if (pathInfo != null) {
  63. // Use path info if available. Indicates index page within a servlet mapping?
  64. // e.g. with index page: URI="/", servletPath="/index.html"
  65. return pathInfo;
  66. }
  67. if (!this.urlDecode) {
  68. // No path info... (not mapped by prefix, nor by extension, nor "/*")
  69. // For the default servlet mapping (i.e. "/"), urlDecode=false can
  70. // cause issues since getServletPath() returns a decoded path.
  71. // If decoding pathWithinApp yields a match just use pathWithinApp.
  72. path = getRemainingPath(decodeInternal(request, pathWithinApp), servletPath, false);
  73. if (path != null) {
  74. return pathWithinApp;
  75. }
  76. }
  77. // Otherwise, use the full servlet path.
  78. return servletPath;
  79. }
  80. }
  81.  
  82. // org.springframework.web.servlet.handler.AbstractHandlerMethodMapping
  83. /**
  84. * Look up the best-matching handler method for the current request.
  85. * If multiple matches are found, the best match is selected.
  86. * @param lookupPath mapping lookup path within the current servlet mapping
  87. * @param request the current request
  88. * @return the best-matching handler method, or {@code null} if no match
  89. * @see #handleMatch(Object, String, HttpServletRequest)
  90. * @see #handleNoMatch(Set, String, HttpServletRequest)
  91. */
  92. protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
  93. List<Match> matches = new ArrayList<Match>();
  94. List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
  95. if (directPathMatches != null) {
  96. // 添加到匹配中,考虑不止一个匹配
  97. addMatchingMappings(directPathMatches, matches, request);
  98. }
  99. if (matches.isEmpty()) {
  100. // No choice but to go through all mappings...
  101. addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
  102. }
  103.  
  104. if (!matches.isEmpty()) {
  105. // 如果有多个匹配,进行优先级排序,判断是否可用,然后取第一个作为最终的 handler
  106. Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
  107. Collections.sort(matches, comparator);
  108. if (logger.isTraceEnabled()) {
  109. logger.trace("Found " + matches.size() + " matching mapping(s) for [" +
  110. lookupPath + "] : " + matches);
  111. }
  112. Match bestMatch = matches.get(0);
  113. if (matches.size() > 1) {
  114. if (CorsUtils.isPreFlightRequest(request)) {
  115. return PREFLIGHT_AMBIGUOUS_MATCH;
  116. }
  117. Match secondBestMatch = matches.get(1);
  118. if (comparator.compare(bestMatch, secondBestMatch) == 0) {
  119. Method m1 = bestMatch.handlerMethod.getMethod();
  120. Method m2 = secondBestMatch.handlerMethod.getMethod();
  121. throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +
  122. request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
  123. }
  124. }
  125. // 解析参数到 handlerMethod 中
  126. handleMatch(bestMatch.mapping, lookupPath, request);
  127. return bestMatch.handlerMethod;
  128. }
  129. else {
  130. return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
  131. }
  132. }
  133.  
  134. // AbstractHandlerMethodMapping$MappingRegistry.getMappingsByUrl()
  135. /**
  136. * Return matches for the given URL path. Not thread-safe.
  137. * @see #acquireReadLock()
  138. */
  139. public List<T> getMappingsByUrl(String urlPath) {
  140. // private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<String, T>();
  141. // 内部使用 Map<K, List<V>> targetMap; 进行保存关系映射
  142. return this.urlLookup.get(urlPath);
  143. }
  144.  
  145. // AbstractHandlerMethodMapping, 将确实有效的mapping添加到 matches 中
  146. private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
  147. for (T mapping : mappings) {
  148. // 重新严格校验路径,参数,header, 返回新的mapping
  149. T match = getMatchingMapping(mapping, request);
  150. if (match != null) {
  151. // 将 handler 放入 match
  152. // private class Match {}
  153. matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
  154. }
  155. }
  156. }

// org.springframework.web.servlet.mvc.condition.HeadersRequestCondition
// org.springframework.web.servlet.mvc.method.RequestMappingInfo
// 进行参数校验,并封装返回参数信息到 RequestMappingInfo 中返回

  1. /**
  2. * Checks if all conditions in this request mapping info match the provided request and returns
  3. * a potentially new request mapping info with conditions tailored to the current request.
  4. * <p>For example the returned instance may contain the subset of URL patterns that match to
  5. * the current request, sorted with best matching patterns on top.
  6. * @return a new instance in case all conditions match; or {@code null} otherwise
  7. */
  8. @Override
  9. public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
  10. RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
  11. ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
  12. HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);
  13. ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);
  14. ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);
  15.  
  16. // 其中某个不匹配,则返回 null
  17. if (methods == null || params == null || headers == null || consumes == null || produces == null) {
  18. return null;
  19. }
  20.  
  21. PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request);
  22. if (patterns == null) {
  23. return null;
  24. }
  25.  
  26. RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);
  27. if (custom == null) {
  28. return null;
  29. }
  30.  
  31. return new RequestMappingInfo(this.name, patterns,
  32. methods, params, headers, consumes, produces, custom.getCondition());
  33. }
  1. /**
  2. * Expose URI template variables, matrix variables, and producible media types in the request.
  3. * @see HandlerMapping#URI_TEMPLATE_VARIABLES_ATTRIBUTE
  4. * @see HandlerMapping#MATRIX_VARIABLES_ATTRIBUTE
  5. * @see HandlerMapping#PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE
  6. */
  7. @Override
  8. protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) {
  9. super.handleMatch(info, lookupPath, request);
  10.  
  11. String bestPattern;
  12. Map<String, String> uriVariables;
  13. Map<String, String> decodedUriVariables;
  14.  
  15. Set<String> patterns = info.getPatternsCondition().getPatterns();
  16. if (patterns.isEmpty()) {
  17. bestPattern = lookupPath;
  18. uriVariables = Collections.emptyMap();
  19. decodedUriVariables = Collections.emptyMap();
  20. }
  21. else {
  22. bestPattern = patterns.iterator().next();
  23. uriVariables = getPathMatcher().extractUriTemplateVariables(bestPattern, lookupPath);
  24. decodedUriVariables = getUrlPathHelper().decodePathVariables(request, uriVariables);
  25. }
  26.  
  27. request.setAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, bestPattern);
  28. request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, decodedUriVariables);
  29.  
  30. if (isMatrixVariableContentAvailable()) {
  31. Map<String, MultiValueMap<String, String>> matrixVars = extractMatrixVariables(request, uriVariables);
  32. request.setAttribute(HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE, matrixVars);
  33. }
  34.  
  35. if (!info.getProducesCondition().getProducibleMediaTypes().isEmpty()) {
  36. Set<MediaType> mediaTypes = info.getProducesCondition().getProducibleMediaTypes();
  37. request.setAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes);
  38. }
  39. }

// org.springframework.web.method.HandlerMethod.createWithResolvedBean(), 重新包装一个带bean实例的 HandlerMethod

  1. /**
  2. * If the provided instance contains a bean name rather than an object instance,
  3. * the bean name is resolved before a {@link HandlerMethod} is created and returned.
  4. */
  5. public HandlerMethod createWithResolvedBean() {
  6. Object handler = this.bean;
  7. if (this.bean instanceof String) {
  8. String beanName = (String) this.bean;
  9. // spring beans 组件
  10. handler = this.beanFactory.getBean(beanName);
  11. }
  12. return new HandlerMethod(this, handler);
  13. }
  1. /**
  2. * Build a {@link HandlerExecutionChain} for the given handler, including
  3. * applicable interceptors.
  4. * <p>The default implementation builds a standard {@link HandlerExecutionChain}
  5. * with the given handler, the handler mapping's common interceptors, and any
  6. * {@link MappedInterceptor}s matching to the current request URL. Interceptors
  7. * are added in the order they were registered. Subclasses may override this
  8. * in order to extend/rearrange the list of interceptors.
  9. * <p><b>NOTE:</b> The passed-in handler object may be a raw handler or a
  10. * pre-built {@link HandlerExecutionChain}. This method should handle those
  11. * two cases explicitly, either building a new {@link HandlerExecutionChain}
  12. * or extending the existing chain.
  13. * <p>For simply adding an interceptor in a custom subclass, consider calling
  14. * {@code super.getHandlerExecutionChain(handler, request)} and invoking
  15. * {@link HandlerExecutionChain#addInterceptor} on the returned chain object.
  16. * @param handler the resolved handler instance (never {@code null})
  17. * @param request current HTTP request
  18. * @return the HandlerExecutionChain (never {@code null})
  19. * @see #getAdaptedInterceptors()
  20. */
  21. protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
  22. HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
  23. (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
  24.  
  25. String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
  26. for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
  27. if (interceptor instanceof MappedInterceptor) {
  28. MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
  29. if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
  30. // 取出内层的 interceptor 使用
  31. chain.addInterceptor(mappedInterceptor.getInterceptor());
  32. }
  33. }
  34. else {
  35. chain.addInterceptor(interceptor);
  36. }
  37. }
  38. return chain;
  39. }

// 获取 adapter,适配不同类型的调用

  1. // org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
  2. // org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter
  3. // org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
  4. /**
  5. * Return the HandlerAdapter for this handler object.
  6. * @param handler the handler object to find an adapter for
  7. * @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.
  8. */
  9. protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
  10. for (HandlerAdapter ha : this.handlerAdapters) {
  11. if (logger.isTraceEnabled()) {
  12. logger.trace("Testing handler adapter [" + ha + "]");
  13. }
  14. if (ha.supports(handler)) {
  15. return ha;
  16. }
  17. }
  18. throw new ServletException("No adapter for handler [" + handler +
  19. "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
  20. }

// mappedHandler.applyPreHandle(processedRequest, response) , 前置调用处理, interceptor 拦截调用

  1. /**
  2. * Apply preHandle methods of registered interceptors.
  3. * @return {@code true} if the execution chain should proceed with the
  4. * next interceptor or the handler itself. Else, DispatcherServlet assumes
  5. * that this interceptor has already dealt with the response itself.
  6. */
  7. boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
  8. HandlerInterceptor[] interceptors = getInterceptors();
  9. if (!ObjectUtils.isEmpty(interceptors)) {
  10. for (int i = 0; i < interceptors.length; i++) {
  11. HandlerInterceptor interceptor = interceptors[i];
  12. // 接收 preHandle 返回值, false 则终止
  13. if (!interceptor.preHandle(request, response, this.handler)) {
  14. triggerAfterCompletion(request, response, null);
  15. return false;
  16. }
  17. this.interceptorIndex = i;
  18. }
  19. }
  20. return true;
  21. }

// mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); 真正调用 handler 处理业务
// org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
// method.AbstractHandlerMethodAdapter

  1. /**
  2. * This implementation expects the handler to be an {@link HandlerMethod}.
  3. */
  4. @Override
  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. @Override
  13. protected ModelAndView handleInternal(HttpServletRequest request,
  14. HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
  15.  
  16. ModelAndView mav;
  17. // 预检查是否可支持
  18. checkRequest(request);
  19.  
  20. // Execute invokeHandlerMethod in synchronized block if required.
  21. if (this.synchronizeOnSession) {
  22. HttpSession session = request.getSession(false);
  23. if (session != null) {
  24. Object mutex = WebUtils.getSessionMutex(session);
  25. synchronized (mutex) {
  26. mav = invokeHandlerMethod(request, response, handlerMethod);
  27. }
  28. }
  29. else {
  30. // No HttpSession available -> no mutex necessary
  31. mav = invokeHandlerMethod(request, response, handlerMethod);
  32. }
  33. }
  34. else {
  35. // No synchronization on session demanded at all...
  36. // invoke
  37. mav = invokeHandlerMethod(request, response, handlerMethod);
  38. }
  39.  
  40. if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
  41. if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
  42. applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
  43. }
  44. else {
  45. prepareResponse(response);
  46. }
  47. }
  48.  
  49. return mav;
  50. }
  1. //org.springframework.web.servlet.support.WebContentGenerator.checkRequest()
  2. /**
  3. * Check the given request for supported methods and a required session, if any.
  4. * @param request current HTTP request
  5. * @throws ServletException if the request cannot be handled because a check failed
  6. * @since 4.2
  7. */
  8. protected final void checkRequest(HttpServletRequest request) throws ServletException {
  9. // Check whether we should support the request method.
  10. String method = request.getMethod();
  11. if (this.supportedMethods != null && !this.supportedMethods.contains(method)) {
  12. throw new HttpRequestMethodNotSupportedException(method, this.supportedMethods);
  13. }
  14.  
  15. // Check whether a session is required.
  16. if (this.requireSession && request.getSession(false) == null) {
  17. throw new HttpSessionRequiredException("Pre-existing session required but none found");
  18. }
  19. }

// 调用 Adapter 的 handler 处理方法

  1. /**
  2. * Invoke the {@link RequestMapping} handler method preparing a {@link ModelAndView}
  3. * if view resolution is required.
  4. * @since 4.2
  5. * @see #createInvocableHandlerMethod(HandlerMethod)
  6. */
  7. protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
  8. HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
  9.  
  10. ServletWebRequest webRequest = new ServletWebRequest(request, response);
  11. try {
  12. // 获取参数绑定工厂
  13. WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
  14. // 参数解析
  15. ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
  16.  
  17. // createInvocableHandlerMethod, 反射调用工具类
  18. ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
  19. invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
  20. invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
  21. invocableMethod.setDataBinderFactory(binderFactory);
  22. invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
  23.  
  24. // mav
  25. ModelAndViewContainer mavContainer = new ModelAndViewContainer();
  26. mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
  27. modelFactory.initModel(webRequest, mavContainer, invocableMethod);
  28. mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
  29.  
  30. AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
  31. asyncWebRequest.setTimeout(this.asyncRequestTimeout);
  32.  
  33. WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
  34. asyncManager.setTaskExecutor(this.taskExecutor);
  35. asyncManager.setAsyncWebRequest(asyncWebRequest);
  36. asyncManager.registerCallableInterceptors(this.callableInterceptors);
  37. asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
  38.  
  39. if (asyncManager.hasConcurrentResult()) {
  40. Object result = asyncManager.getConcurrentResult();
  41. mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
  42. asyncManager.clearConcurrentResult();
  43. if (logger.isDebugEnabled()) {
  44. logger.debug("Found concurrent result value [" + result + "]");
  45. }
  46. invocableMethod = invocableMethod.wrapConcurrentResult(result);
  47. }
  48.  
  49. // 调用业务 controller
  50. invocableMethod.invokeAndHandle(webRequest, mavContainer);
  51. if (asyncManager.isConcurrentHandlingStarted()) {
  52. return null;
  53. }
  54.  
  55. // 返回 mv, jsp, 如果是 json 一类的输出,则直接返回 null
  56. return getModelAndView(mavContainer, modelFactory, webRequest);
  57. }
  58. finally {
  59. webRequest.requestCompleted();
  60. }
  61. }

细节点的工厂类创建:

  1. // 参数绑定工厂
  2. private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
  3. Class<?> handlerType = handlerMethod.getBeanType();
  4. Set<Method> methods = this.initBinderCache.get(handlerType);
  5. if (methods == null) {
  6. methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);
  7. this.initBinderCache.put(handlerType, methods);
  8. }
  9. List<InvocableHandlerMethod> initBinderMethods = new ArrayList<InvocableHandlerMethod>();
  10. // Global methods first
  11. for (Entry<ControllerAdviceBean, Set<Method>> entry : this.initBinderAdviceCache.entrySet()) {
  12. if (entry.getKey().isApplicableToBeanType(handlerType)) {
  13. Object bean = entry.getKey().resolveBean();
  14. for (Method method : entry.getValue()) {
  15. initBinderMethods.add(createInitBinderMethod(bean, method));
  16. }
  17. }
  18. }
  19. for (Method method : methods) {
  20. Object bean = handlerMethod.getBean();
  21. initBinderMethods.add(createInitBinderMethod(bean, method));
  22. }
  23. return createDataBinderFactory(initBinderMethods);
  24. }
  25.  
  26. // 参数解析工厂
  27. private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
  28. SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
  29. Class<?> handlerType = handlerMethod.getBeanType();
  30. Set<Method> methods = this.modelAttributeCache.get(handlerType);
  31. if (methods == null) {
  32. methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);
  33. this.modelAttributeCache.put(handlerType, methods);
  34. }
  35. List<InvocableHandlerMethod> attrMethods = new ArrayList<InvocableHandlerMethod>();
  36. // Global methods first
  37. for (Entry<ControllerAdviceBean, Set<Method>> entry : this.modelAttributeAdviceCache.entrySet()) {
  38. if (entry.getKey().isApplicableToBeanType(handlerType)) {
  39. Object bean = entry.getKey().resolveBean();
  40. for (Method method : entry.getValue()) {
  41. attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
  42. }
  43. }
  44. }
  45. for (Method method : methods) {
  46. Object bean = handlerMethod.getBean();
  47. attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
  48. }
  49. return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);
  50. }

// org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle()

  1. /**
  2. * Invoke the method and handle the return value through one of the
  3. * configured {@link HandlerMethodReturnValueHandler}s.
  4. * @param webRequest the current request
  5. * @param mavContainer the ModelAndViewContainer for this request
  6. * @param providedArgs "given" arguments matched by type (not resolved)
  7. */
  8. public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
  9. Object... providedArgs) throws Exception {
  10.  
  11. // 直接调用 handler
  12. Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
  13. // 设置响应码
  14. setResponseStatus(webRequest);
  15.  
  16. if (returnValue == null) {
  17. if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
  18. mavContainer.setRequestHandled(true);
  19. return;
  20. }
  21. }
  22. else if (StringUtils.hasText(getResponseStatusReason())) {
  23. mavContainer.setRequestHandled(true);
  24. return;
  25. }
  26.  
  27. mavContainer.setRequestHandled(false);
  28. try {
  29. // 处理返回值
  30. this.returnValueHandlers.handleReturnValue(
  31. returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
  32. }
  33. catch (Exception ex) {
  34. if (logger.isTraceEnabled()) {
  35. logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
  36. }
  37. throw ex;
  38. }
  39. }
  40.  
  41. // InvocableHandlerMethod.invokeForRequest()
  42. /**
  43. * Invoke the method after resolving its argument values in the context of the given request.
  44. * <p>Argument values are commonly resolved through {@link HandlerMethodArgumentResolver}s.
  45. * The {@code providedArgs} parameter however may supply argument values to be used directly,
  46. * i.e. without argument resolution. Examples of provided argument values include a
  47. * {@link WebDataBinder}, a {@link SessionStatus}, or a thrown exception instance.
  48. * Provided argument values are checked before argument resolvers.
  49. * @param request the current request
  50. * @param mavContainer the ModelAndViewContainer for this request
  51. * @param providedArgs "given" arguments matched by type, not resolved
  52. * @return the raw value returned by the invoked method
  53. * @exception Exception raised if no suitable argument resolver can be found,
  54. * or if the method raised an exception
  55. */
  56. public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
  57. Object... providedArgs) throws Exception {
  58.  
  59. // 获取方法参数
  60. Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
  61. if (logger.isTraceEnabled()) {
  62. logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
  63. "' with arguments " + Arrays.toString(args));
  64. }
  65. // invoke
  66. Object returnValue = doInvoke(args);
  67. if (logger.isTraceEnabled()) {
  68. logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
  69. "] returned [" + returnValue + "]");
  70. }
  71. return returnValue;
  72. }

// 参数封装,InvocableHandlerMethod.getMethodArgumentValues()

  1. // InvocableHandlerMethod.getMethodArgumentValues()
  2. /**
  3. * Get the method argument values for the current request.
  4. */
  5. private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
  6. Object... providedArgs) throws Exception {
  7.  
  8. MethodParameter[] parameters = getMethodParameters();
  9. Object[] args = new Object[parameters.length];
  10. for (int i = 0; i < parameters.length; i++) {
  11. MethodParameter parameter = parameters[i];
  12. parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
  13. args[i] = resolveProvidedArgument(parameter, providedArgs);
  14. if (args[i] != null) {
  15. continue;
  16. }
  17. if (this.argumentResolvers.supportsParameter(parameter)) {
  18. try {
  19. args[i] = this.argumentResolvers.resolveArgument(
  20. parameter, mavContainer, request, this.dataBinderFactory);
  21. continue;
  22. }
  23. catch (Exception ex) {
  24. if (logger.isDebugEnabled()) {
  25. logger.debug(getArgumentResolutionErrorMessage("Failed to resolve", i), ex);
  26. }
  27. throw ex;
  28. }
  29. }
  30. if (args[i] == null) {
  31. throw new IllegalStateException("Could not resolve method parameter at index " +
  32. parameter.getParameterIndex() + " in " + parameter.getMethod().toGenericString() +
  33. ": " + getArgumentResolutionErrorMessage("No suitable resolver for", i));
  34. }
  35. }
  36. return args;
  37. }
  38.  
  39. // org.springframework.web.method.support.HandlerMethodArgumentResolverComposite
  40. /**
  41. * Iterate over registered {@link HandlerMethodArgumentResolver}s and invoke the one that supports it.
  42. * @throws IllegalStateException if no suitable {@link HandlerMethodArgumentResolver} is found.
  43. */
  44. @Override
  45. public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
  46. NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
  47.  
  48. HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
  49. if (resolver == null) {
  50. throw new IllegalArgumentException("Unknown parameter type [" + parameter.getParameterType().getName() + "]");
  51. }
  52. return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
  53. }
  54.  
  55. // AbstractNamedValueMethodArgumentResolver
  56.  
  57. @Override
  58. public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
  59. NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
  60.  
  61. NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
  62. MethodParameter nestedParameter = parameter.nestedIfOptional();
  63.  
  64. // 处理 key
  65. Object resolvedName = resolveStringValue(namedValueInfo.name);
  66. if (resolvedName == null) {
  67. throw new IllegalArgumentException(
  68. "Specified name must not resolve to null: [" + namedValueInfo.name + "]");
  69. }
  70.  
  71. // 获取 value
  72. Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
  73. if (arg == null) {
  74. if (namedValueInfo.defaultValue != null) {
  75. arg = resolveStringValue(namedValueInfo.defaultValue);
  76. }
  77. else if (namedValueInfo.required && !nestedParameter.isOptional()) {
  78. handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
  79. }
  80. arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
  81. }
  82. else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
  83. arg = resolveStringValue(namedValueInfo.defaultValue);
  84. }
  85.  
  86. if (binderFactory != null) {
  87. WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
  88. try {
  89. arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
  90. }
  91. catch (ConversionNotSupportedException ex) {
  92. throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(),
  93. namedValueInfo.name, parameter, ex.getCause());
  94. }
  95. catch (TypeMismatchException ex) {
  96. throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(),
  97. namedValueInfo.name, parameter, ex.getCause());
  98.  
  99. }
  100. }
  101.  
  102. handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
  103.  
  104. return arg;
  105. }

// Object returnValue = doInvoke(args); 
// InvocableHandlerMethod.doInvoke(), 正常返回结果,异常包装返回

  1. /**
  2. * Invoke the handler method with the given argument values.
  3. */
  4. protected Object doInvoke(Object... args) throws Exception {
  5. // 确保方法可调用
  6. ReflectionUtils.makeAccessible(getBridgedMethod());
  7. try {
  8. // 调用业务方法
  9. return getBridgedMethod().invoke(getBean(), args);
  10. }
  11. catch (IllegalArgumentException ex) {
  12. assertTargetBean(getBridgedMethod(), getBean(), args);
  13. String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
  14. throw new IllegalStateException(getInvocationErrorMessage(text, args), ex);
  15. }
  16. catch (InvocationTargetException ex) {
  17. // Unwrap for HandlerExceptionResolvers ...
  18. Throwable targetException = ex.getTargetException();
  19. if (targetException instanceof RuntimeException) {
  20. throw (RuntimeException) targetException;
  21. }
  22. else if (targetException instanceof Error) {
  23. throw (Error) targetException;
  24. }
  25. else if (targetException instanceof Exception) {
  26. throw (Exception) targetException;
  27. }
  28. else {
  29. String text = getInvocationErrorMessage("Failed to invoke handler method", args);
  30. throw new IllegalStateException(text, targetException);
  31. }
  32. }
  33. }

// 至此业务方法终于调用完成

// 接下来,处理返回值

  1. // this.returnValueHandlers.handleReturnValue(
  2. // returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
  3. // org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue()
  4. /**
  5. * Iterate over registered {@link HandlerMethodReturnValueHandler}s and invoke the one that supports it.
  6. * @throws IllegalStateException if no suitable {@link HandlerMethodReturnValueHandler} is found.
  7. */
  8. @Override
  9. public void handleReturnValue(Object returnValue, MethodParameter returnType,
  10. ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
  11.  
  12. HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
  13. if (handler == null) {
  14. throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
  15. }
  16. handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
  17. }
  18.  
  19. // 返回值处理器
  20. // org.springframework.web.servlet.mvc.method.annotation.ModelAndViewMethodReturnValueHandler
  21. // org.springframework.web.method.annotation.ModelMethodProcessor
  22. // org.springframework.web.servlet.mvc.method.annotation.ViewMethodReturnValueHandler
  23. // org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitterReturnValueHandler
  24. // org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBodyReturnValueHandler
  25. // org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor
  26. // org.springframework.web.servlet.mvc.method.annotation.HttpHeadersReturnValueHandler
  27. // org.springframework.web.servlet.mvc.method.annotation.CallableMethodReturnValueHandler
  28. // org.springframework.web.servlet.mvc.method.annotation.DeferredResultMethodReturnValueHandler
  29. // org.springframework.web.servlet.mvc.method.annotation.AsyncTaskMethodReturnValueHandler
  30. // org.springframework.web.method.annotation.ModelAttributeMethodProcessor
  31. // org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor
  32. // org.springframework.web.servlet.mvc.method.annotation.ViewNameMethodReturnValueHandler
  33. // org.springframework.web.method.annotation.MapMethodProcessor
  34. // org.springframework.web.method.annotation.ModelAttributeMethodProcessor
  35. private HandlerMethodReturnValueHandler selectHandler(Object value, MethodParameter returnType) {
  36. boolean isAsyncValue = isAsyncReturnValue(value, returnType);
  37. for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
  38. if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
  39. continue;
  40. }
  41. // return Callable.class.isAssignableFrom(returnType.getParameterType());
  42. // return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
  43. // returnType.hasMethodAnnotation(ResponseBody.class));
  44. if (handler.supportsReturnType(returnType)) {
  45. return handler;
  46. }
  47. }
  48. return null;
  49. }
  50.  
  51. // org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(), 处理返回结果
  52. @Override
  53. public void handleReturnValue(Object returnValue, MethodParameter returnType,
  54. ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
  55. throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
  56.  
  57. mavContainer.setRequestHandled(true);
  58. ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
  59. ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
  60.  
  61. // 写返回值
  62. // Try even with null return value. ResponseBodyAdvice could get involved.
  63. writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
  64. }
  65.  
  66. /**
  67. * Creates a new {@link HttpOutputMessage} from the given {@link NativeWebRequest}.
  68. * @param webRequest the web request to create an output message from
  69. * @return the output message
  70. */
  71. protected ServletServerHttpResponse createOutputMessage(NativeWebRequest webRequest) {
  72. HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
  73. return new ServletServerHttpResponse(response);
  74. }
  75.  
  76. /**
  77. * Writes the given return type to the given output message.
  78. * @param value the value to write to the output message
  79. * @param returnType the type of the value
  80. * @param inputMessage the input messages. Used to inspect the {@code Accept} header.
  81. * @param outputMessage the output message to write to
  82. * @throws IOException thrown in case of I/O errors
  83. * @throws HttpMediaTypeNotAcceptableException thrown when the conditions indicated
  84. * by the {@code Accept} header on the request cannot be met by the message converters
  85. */
  86. @SuppressWarnings("unchecked")
  87. protected <T> void writeWithMessageConverters(T value, MethodParameter returnType,
  88. ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
  89. throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
  90.  
  91. Object outputValue;
  92. Class<?> valueType;
  93. Type declaredType;
  94.  
  95. if (value instanceof CharSequence) {
  96. // string 的返回值输出
  97. outputValue = value.toString();
  98. valueType = String.class;
  99. declaredType = String.class;
  100. }
  101. else {
  102. outputValue = value;
  103. valueType = getReturnValueType(outputValue, returnType);
  104. declaredType = getGenericType(returnType);
  105. }
  106.  
  107. HttpServletRequest request = inputMessage.getServletRequest();
  108. // 获取返回的 content-type 值
  109. List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(request);
  110. List<MediaType> producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType);
  111.  
  112. if (outputValue != null && producibleMediaTypes.isEmpty()) {
  113. throw new IllegalArgumentException("No converter found for return value of type: " + valueType);
  114. }
  115.  
  116. Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>();
  117. for (MediaType requestedType : requestedMediaTypes) {
  118. for (MediaType producibleType : producibleMediaTypes) {
  119. if (requestedType.isCompatibleWith(producibleType)) {
  120. compatibleMediaTypes.add(getMostSpecificMediaType(requestedType, producibleType));
  121. }
  122. }
  123. }
  124. if (compatibleMediaTypes.isEmpty()) {
  125. if (outputValue != null) {
  126. throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes);
  127. }
  128. return;
  129. }
  130.  
  131. List<MediaType> mediaTypes = new ArrayList<MediaType>(compatibleMediaTypes);
  132. MediaType.sortBySpecificityAndQuality(mediaTypes);
  133.  
  134. // 确定输出的类型
  135. MediaType selectedMediaType = null;
  136. for (MediaType mediaType : mediaTypes) {
  137. if (mediaType.isConcrete()) {
  138. selectedMediaType = mediaType;
  139. break;
  140. }
  141. else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICATION)) {
  142. selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;
  143. break;
  144. }
  145. }
  146.  
  147. if (selectedMediaType != null) {
  148. selectedMediaType = selectedMediaType.removeQualityValue();
  149. // 使用 messageConverter 进行返回值转换
  150. // org.springframework.http.converter.ByteArrayHttpMessageConverter
  151. // org.springframework.http.converter.StringHttpMessageConverter
  152. // org.springframework.http.converter.ResourceHttpMessageConverter
  153. // org.springframework.http.converter.xml.SourceHttpMessageConverter
  154. // org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter
  155. // org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter
  156. // org.springframework.http.converter.ByteArrayHttpMessageConverter
  157. // org.springframework.http.converter.StringHttpMessageConverter
  158. // org.springframework.http.converter.ResourceHttpMessageConverter
  159. // org.springframework.http.converter.xml.SourceHttpMessageConverter
  160. // org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter
  161. // org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter
  162. for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
  163. if (messageConverter instanceof GenericHttpMessageConverter) {
  164. if (((GenericHttpMessageConverter) messageConverter).canWrite(
  165. declaredType, valueType, selectedMediaType)) {
  166. outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType,
  167. (Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(),
  168. inputMessage, outputMessage);
  169. if (outputValue != null) {
  170. addContentDispositionHeader(inputMessage, outputMessage);
  171. ((GenericHttpMessageConverter) messageConverter).write(
  172. outputValue, declaredType, selectedMediaType, outputMessage);
  173. if (logger.isDebugEnabled()) {
  174. logger.debug("Written [" + outputValue + "] as \"" + selectedMediaType +
  175. "\" using [" + messageConverter + "]");
  176. }
  177. }
  178. return;
  179. }
  180. }
  181. else if (messageConverter.canWrite(valueType, selectedMediaType)) {
  182. // 输出值
  183. outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType,
  184. (Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(),
  185. inputMessage, outputMessage);
  186. if (outputValue != null) {
  187. addContentDispositionHeader(inputMessage, outputMessage);
  188. // write
  189. ((HttpMessageConverter) messageConverter).write(outputValue, selectedMediaType, outputMessage);
  190. if (logger.isDebugEnabled()) {
  191. logger.debug("Written [" + outputValue + "] as \"" + selectedMediaType +
  192. "\" using [" + messageConverter + "]");
  193. }
  194. }
  195. return;
  196. }
  197. }
  198. }
  199.  
  200. if (outputValue != null) {
  201. throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);
  202. }
  203. }

// 消息转换器

// org.springframework.http.converter.StringHttpMessageConverter
// org.springframework.http.converter.AbstractHttpMessageConverter

  1. // org.springframework.http.converter.StringHttpMessageConverter
  2. // org.springframework.http.converter.AbstractHttpMessageConverter
  3. /**
  4. * This implementation sets the default headers by calling {@link #addDefaultHeaders},
  5. * and then calls {@link #writeInternal}.
  6. */
  7. @Override
  8. public final void write(final T t, MediaType contentType, HttpOutputMessage outputMessage)
  9. throws IOException, HttpMessageNotWritableException {
  10.  
  11. final HttpHeaders headers = outputMessage.getHeaders();
  12. addDefaultHeaders(headers, t, contentType);
  13.  
  14. if (outputMessage instanceof StreamingHttpOutputMessage) {
  15. StreamingHttpOutputMessage streamingOutputMessage =
  16. (StreamingHttpOutputMessage) outputMessage;
  17. streamingOutputMessage.setBody(new StreamingHttpOutputMessage.Body() {
  18. @Override
  19. public void writeTo(final OutputStream outputStream) throws IOException {
  20. writeInternal(t, new HttpOutputMessage() {
  21. @Override
  22. public OutputStream getBody() throws IOException {
  23. return outputStream;
  24. }
  25. @Override
  26. public HttpHeaders getHeaders() {
  27. return headers;
  28. }
  29. });
  30. }
  31. });
  32. }
  33. else {
  34. // write
  35. writeInternal(t, outputMessage);
  36. // 再次 flush()
  37. outputMessage.getBody().flush();
  38. }
  39. }
  40.  
  41. // StringHttpMessageConverter
  42. @Override
  43. protected void writeInternal(String str, HttpOutputMessage outputMessage) throws IOException {
  44. if (this.writeAcceptCharset) {
  45. outputMessage.getHeaders().setAcceptCharset(getAcceptedCharsets());
  46. }
  47. Charset charset = getContentTypeCharset(outputMessage.getHeaders().getContentType());
  48. StreamUtils.copy(str, charset, outputMessage.getBody());
  49. }
  50.  
  51. // org.springframework.util.StreamUtils.copy()
  52. // 像socket中写入返回值,即向浏览器一类请求客户端输出返回值,到此,客户端得到响应
  53. /**
  54. * Copy the contents of the given String to the given output OutputStream.
  55. * Leaves the stream open when done.
  56. * @param in the String to copy from
  57. * @param charset the Charset
  58. * @param out the OutputStream to copy to
  59. * @throws IOException in case of I/O errors
  60. */
  61. public static void copy(String in, Charset charset, OutputStream out) throws IOException {
  62. Assert.notNull(in, "No input String specified");
  63. Assert.notNull(charset, "No charset specified");
  64. Assert.notNull(out, "No OutputStream specified");
  65.  
  66. Writer writer = new OutputStreamWriter(out, charset);
  67. writer.write(in);
  68. writer.flush();
  69. }

// return getModelAndView(mavContainer, modelFactory, webRequest);
// RequestMappingHandlerAdapter

  1. // return getModelAndView(mavContainer, modelFactory, webRequest);
  2. // RequestMappingHandlerAdapter
  3. private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
  4. ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
  5.  
  6. // 如果已经处理完成,返回null
  7. modelFactory.updateModel(webRequest, mavContainer);
  8. if (mavContainer.isRequestHandled()) {
  9. return null;
  10. }
  11. // 否则处理 mv
  12. ModelMap model = mavContainer.getModel();
  13. ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
  14. if (!mavContainer.isViewReference()) {
  15. mav.setView((View) mavContainer.getView());
  16. }
  17. if (model instanceof RedirectAttributes) {
  18. Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
  19. HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
  20. RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
  21. }
  22. return mav;
  23. }

// prepareResponse(response);
// RequestMappingHandlerAdapter

  1. /**
  2. * Prepare the given response according to the settings of this generator.
  3. * Applies the number of cache seconds specified for this generator.
  4. * @param response current HTTP response
  5. * @since 4.2
  6. */
  7. protected final void prepareResponse(HttpServletResponse response) {
  8. if (this.cacheControl != null) {
  9. applyCacheControl(response, this.cacheControl);
  10. }
  11. else {
  12. applyCacheSeconds(response, this.cacheSeconds);
  13. }
  14. if (servlet3Present && this.varyByRequestHeaders != null) {
  15. for (String value : getVaryRequestHeadersToAdd(response)) {
  16. response.addHeader("Vary", value);
  17. }
  18. }
  19. }

// mappedHandler.applyPostHandle(processedRequest, response, mv);
// org.springframework.web.servlet.HandlerExecutionChain.applyPostHandle(), 调用 interceptor.postHandle()

  1. // org.springframework.web.servlet.HandlerExecutionChain.applyPostHandle(), 调用 interceptor.postHandle()
  2. /**
  3. * Apply postHandle methods of registered interceptors.
  4. */
  5. void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
  6. HandlerInterceptor[] interceptors = getInterceptors();
  7. if (!ObjectUtils.isEmpty(interceptors)) {
  8. for (int i = interceptors.length - 1; i >= 0; i--) {
  9. HandlerInterceptor interceptor = interceptors[i];
  10. interceptor.postHandle(request, response, this.handler, mv);
  11. }
  12. }
  13. }

// processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

  1. /**
  2. * Handle the result of handler selection and handler invocation, which is
  3. * either a ModelAndView or an Exception to be resolved to a ModelAndView.
  4. */
  5. private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
  6. HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
  7.  
  8. boolean errorView = false;
  9.  
  10. // 发生异常,使用 errorView
  11. if (exception != null) {
  12. if (exception instanceof ModelAndViewDefiningException) {
  13. logger.debug("ModelAndViewDefiningException encountered", exception);
  14. mv = ((ModelAndViewDefiningException) exception).getModelAndView();
  15. }
  16. else {
  17. Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
  18. mv = processHandlerException(request, response, handler, exception);
  19. errorView = (mv != null);
  20. }
  21. }
  22.  
  23. // Did the handler return a view to render?
  24. if (mv != null && !mv.wasCleared()) {
  25. render(mv, request, response);
  26. if (errorView) {
  27. WebUtils.clearErrorRequestAttributes(request);
  28. }
  29. }
  30. else {
  31. if (logger.isDebugEnabled()) {
  32. logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
  33. "': assuming HandlerAdapter completed request handling");
  34. }
  35. }
  36.  
  37. if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
  38. // Concurrent handling started during a forward
  39. return;
  40. }
  41.  
  42. if (mappedHandler != null) {
  43. // 最后再一个触发器钩子,触发 interceptor.afterCompletion()
  44. mappedHandler.triggerAfterCompletion(request, response, null);
  45. }
  46. }
  47.  
  48. /**
  49. * Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
  50. * Will just invoke afterCompletion for all interceptors whose preHandle invocation
  51. * has successfully completed and returned true.
  52. */
  53. void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
  54. throws Exception {
  55.  
  56. HandlerInterceptor[] interceptors = getInterceptors();
  57. if (!ObjectUtils.isEmpty(interceptors)) {
  58. for (int i = this.interceptorIndex; i >= 0; i--) {
  59. HandlerInterceptor interceptor = interceptors[i];
  60. try {
  61. interceptor.afterCompletion(request, response, this.handler, ex);
  62. }
  63. catch (Throwable ex2) {
  64. logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
  65. }
  66. }
  67. }
  68. }

// 依次返回 doDispatch(),清理环境
// 返回 FrameworkServlet.doService()

// FrameworkServlet finally中还会触发 requestAttributes.requestCompleted();

  1. // org.springframework.web.context.request.ServletRequestAttributes.requestCompleted()
  2. /**
  3. * Signal that the request has been completed.
  4. * <p>Executes all request destruction callbacks and updates the
  5. * session attributes that have been accessed during request processing.
  6. */
  7. public void requestCompleted() {
  8. executeRequestDestructionCallbacks();
  9. updateAccessedSessionAttributes();
  10. this.requestActive = false;
  11. }
  12.  
  13. /**
  14. * Execute all callbacks that have been registered for execution
  15. * after request completion.
  16. */
  17. private void executeRequestDestructionCallbacks() {
  18. synchronized (this.requestDestructionCallbacks) {
  19. for (Runnable runnable : this.requestDestructionCallbacks.values()) {
  20. // 同步调用 DestructionCallbacks.run()
  21. runnable.run();
  22. }
  23. this.requestDestructionCallbacks.clear();
  24. }
  25. }
  26.  
  27. /**
  28. * Update all accessed session attributes through {@code session.setAttribute}
  29. * calls, explicitly indicating to the container that they might have been modified.
  30. */
  31. @Override
  32. protected void updateAccessedSessionAttributes() {
  33. if (!this.sessionAttributesToUpdate.isEmpty()) {
  34. // Update all affected session attributes.
  35. HttpSession session = getSession(false);
  36. if (session != null) {
  37. try {
  38. for (Map.Entry<String, Object> entry : this.sessionAttributesToUpdate.entrySet()) {
  39. String name = entry.getKey();
  40. Object newValue = entry.getValue();
  41. Object oldValue = session.getAttribute(name);
  42. if (oldValue == newValue && !isImmutableSessionAttribute(name, newValue)) {
  43. session.setAttribute(name, newValue);
  44. }
  45. }
  46. }
  47. catch (IllegalStateException ex) {
  48. // Session invalidated - shouldn't usually happen.
  49. }
  50. }
  51. this.sessionAttributesToUpdate.clear();
  52. }
  53. }
  54.  
  55. // 最后 publishRequestHandledEvent(request, response, startTime, failureCause);
  56. // FrameworkServlet
  57. private void publishRequestHandledEvent(
  58. HttpServletRequest request, HttpServletResponse response, long startTime, Throwable failureCause) {
  59.  
  60. if (this.publishEvents) {
  61. // Whether or not we succeeded, publish an event.
  62. long processingTime = System.currentTimeMillis() - startTime;
  63. int statusCode = (responseGetStatusAvailable ? response.getStatus() : -1);
  64. // 发布 event 到 spring, 使感兴趣的监听者进行相应处理
  65. this.webApplicationContext.publishEvent(
  66. new ServletRequestHandledEvent(this,
  67. request.getRequestURI(), request.getRemoteAddr(),
  68. request.getMethod(), getServletConfig().getServletName(),
  69. WebUtils.getSessionId(request), getUsernameForRequest(request),
  70. processingTime, failureCause, statusCode));
  71. }
  72. }

总结几个技术要点:

1. filterchain 责任链模式的使用;

2. 工厂模式的使用;

3. 拦截器监听;

4. 各功能组件化,职责分明;

5. 模板方法模式使用;

6. mvc;

7. 适配器模式应用;

8. 观察者模式应用;

简单读!spring-mvc源码之穿越http请求的更多相关文章

  1. Spring MVC源码——Root WebApplicationContext

    目录 Spring MVC源码--Root WebApplicationContext 上下文层次结构 Root WebApplicationContext 初始化和销毁 ContextLoaderL ...

  2. 精尽Spring MVC源码分析 - 寻找遗失的 web.xml

    该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...

  3. Spring MVC源码——Servlet WebApplicationContext

    上一篇笔记(Spring MVC源码——Root WebApplicationContext)中记录了下 Root WebApplicationContext 的初始化代码.这一篇来看 Servlet ...

  4. 精尽Spring MVC源码分析 - MultipartResolver 组件

    该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...

  5. 精尽Spring MVC源码分析 - HandlerMapping 组件(一)之 AbstractHandlerMapping

    该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...

  6. 精尽Spring MVC源码分析 - HandlerMapping 组件(四)之 AbstractUrlHandlerMapping

    该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...

  7. 精尽Spring MVC源码分析 - HandlerAdapter 组件(三)之 HandlerMethodArgumentResolver

    该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...

  8. 精尽Spring MVC源码分析 - HandlerAdapter 组件(四)之 HandlerMethodReturnValueHandler

    该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...

  9. 精尽Spring MVC源码分析 - HandlerExceptionResolver 组件

    该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...

随机推荐

  1. C语言编写程序计算圆上的点的坐标

    Problem Description There is a cycle with its center on the origin. Now give you a point on the cycl ...

  2. 谈谈逆向android里面的so

    1. 加密sgf算法分析 2.gnugo瘦身记

  3. centos vi设置tab为4个空格 和括号自动补全

    1.打开vim配置文件 vi /etc/vimrc 2.设置tab为4个空格, 在文件末尾添加以下内容 if has( "autocmd" ) filetype plugin in ...

  4. Isight Linux 2016hf2 安装步骤

    把License文件整个拷进去,都给执行权限 把ABAQUS.lic 里的 this_host 改为psn004 27011 改为26011 (区别于2017hf2) 杀掉2017的server ./ ...

  5. qt布局管理-缩放、多窗口切换

    关于缩放的布局 所有控件要求与主窗口同时缩放,那么在所有控件设置好布局后,最后点击最外侧的主控件,选择水平布局或者垂直布局即可. 另外每个空间的属性可更改,如SizePolicy用于设置空间是否可缩放 ...

  6. python 10 迭代器和三元运算符

    一.迭代器 1.迭代器协议:对象必须提供一种next方法,执行该方法要么返回迭代中的下一项,要么引起一个stopIteration异常,终止迭代 2.可迭代对象:实现了迭代器协议的对象 3.pytho ...

  7. 博客1--tensorflow的图像基本处理操作

    话不多,具体内容在开源中国里我的博客:https://my.oschina.net/u/3770644 代码: #!/usr/bin/env python# -*- coding:utf-8 -*-# ...

  8. PYTHON基础入门(内置函数、推导式)学习

    **内建函数**1.通过使用dir()函数可以列出所具备的方法 例:num = 10 dir(num) 例:myList = [1,2,3,4,5,6] dir(num)2.通过使用help()函数可 ...

  9. mac ssh,mac xshell,xshell替代,ssh客户端,ssh工具,远程桌面加速

    下载地址 Windows版下载地址:http://www.hostbuf.com/downloads/finalshell_install.exe Mac版,Linux版安装及教程:http://ww ...

  10. svn的基本使用方法

    一,svn的介绍 Subversion(SVN) 是一个开源的版本控制系統, 也就是说 Subversion 管理着随时间改变的数据. 这些数据放置在一个中央资料档案库(repository) 中. ...