Spring DispatcherServlet的请求转发流程(源码分析)
想要了解框架的处理流程,最好的方法是直接Debug它的源码。这里主要涉及到的有三个类:
DispatcherServlet
FrameworkServlet
HttpServlet
它们从上到下是继承关系,其中DispatcherServlet和FrameworkServlet是Spring框架实现的。
而HttpServlet是Web容器实现的(比如Tomcat),在Tomcat中,HttpServlet -> GenericServlet -> Servlet(接口),还有这样的继承关系。
我们知道,对于客户端请求,是通过servlet的service方法处理的,GenericServlet实现了Servlet接口,但是它的service方法仍然是一个抽象方法,其具体内容是由继承它的HttpServlet实现的。
在HttpServlet中有这样两段源码:
1 protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 2 String method = req.getMethod(); 3 long lastModified; 4 if (method.equals("GET")) { 5 lastModified = this.getLastModified(req); 6 if (lastModified == -1L) { 7 this.doGet(req, resp); 8 } else { 9 long ifModifiedSince; 10 try { 11 ifModifiedSince = req.getDateHeader("If-Modified-Since"); 12 } catch (IllegalArgumentException var9) { 13 ifModifiedSince = -1L; 14 } 15 16 if (ifModifiedSince < lastModified / 1000L * 1000L) { 17 this.maybeSetLastModified(resp, lastModified); 18 this.doGet(req, resp); 19 } else { 20 resp.setStatus(304); 21 } 22 } 23 } else if (method.equals("HEAD")) { 24 lastModified = this.getLastModified(req); 25 this.maybeSetLastModified(resp, lastModified); 26 this.doHead(req, resp); 27 } else if (method.equals("POST")) { 28 this.doPost(req, resp); 29 } else if (method.equals("PUT")) { 30 this.doPut(req, resp); 31 } else if (method.equals("DELETE")) { 32 this.doDelete(req, resp); 33 } else if (method.equals("OPTIONS")) { 34 this.doOptions(req, resp); 35 } else if (method.equals("TRACE")) { 36 this.doTrace(req, resp); 37 } else { 38 String errMsg = lStrings.getString("http.method_not_implemented"); 39 Object[] errArgs = new Object[]{method}; 40 errMsg = MessageFormat.format(errMsg, errArgs); 41 resp.sendError(501, errMsg); 42 } 43 44 }
1 public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { 2 HttpServletRequest request; 3 HttpServletResponse response; 4 try { 5 request = (HttpServletRequest)req; 6 response = (HttpServletResponse)res; 7 } catch (ClassCastException var6) { 8 throw new ServletException("non-HTTP request or response"); 9 } 10 11 this.service(request, response); 12 }
首先请求到达 service(ServletRequest req, ServletResponse res) 方法,请求中的ServletRequest和ServletResponse将被封装为HttpServletRequest和HttpServletResponse。
封装完成后,交给 service(HttpServletRequest req, HttpServletResponse resp) 这个方法处理。
在 service(HttpServletRequest req, HttpServletResponse resp) 方法中,将根据请求类型,交给不同的doGet,doPost,doPut,doDelete等方法。
这些方法类似于这样:
1 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 2 String protocol = req.getProtocol(); 3 String msg = lStrings.getString("http.method_get_not_supported"); 4 if (protocol.endsWith("1.1")) { 5 resp.sendError(405, msg); 6 } else { 7 resp.sendError(400, msg); 8 } 9 10 }
可见,基本上没有实现什么功能,具体功能是需要由继承它的类去重写的。如果我们使用了Spring框架,就是由FrameworkServlet来实现。
让我们抛开doGet这些方法,先看看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 == HttpMethod.PATCH || httpMethod == null) { 10 processRequest(request, response); 11 } 12 else { 13 super.service(request, response); 14 } 15 }
它重写了HttpServlet中的 service(HttpServletRequest request, HttpServletResponse response) 方法。目的看源码也很清楚,用于支持Http的Patch请求方法(其2010年才成为规范,很多Web容器并不支持,见RFC5789)
对于Patch请求,直接交给processRequest方法,其他类型则交给父类(HttpServlet)的service方法处理,即,根据请求类型,交给doGet,doPost,doPut,doDelete等方法处理。
但是doGet这些方法在父类中没有详细实现功能。让我们再看看FrameworkServlet是怎样重写的:
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 }
1 /** 2 * Delegate POST requests to {@link #processRequest}. 3 * @see #doService 4 */ 5 @Override 6 protected final void doPost(HttpServletRequest request, HttpServletResponse response) 7 throws ServletException, IOException { 8 9 processRequest(request, response); 10 }
其他请求类型的实现大同小异,都要调用processRequest方法:
1 /** 2 * Process this request, publishing an event regardless of the outcome. 3 * <p>The actual event handling is performed by the abstract 4 * {@link #doService} template method. 5 */ 6 protected final void processRequest(HttpServletRequest request, HttpServletResponse response) 7 throws ServletException, IOException { 8 9 long startTime = System.currentTimeMillis(); 10 Throwable failureCause = null; 11 12 LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext(); 13 LocaleContext localeContext = buildLocaleContext(request); 14 15 RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes(); 16 ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes); 17 18 WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); 19 asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor()); 20 21 initContextHolders(request, localeContext, requestAttributes); 22 23 try { 24 doService(request, response); 25 } 26 catch (ServletException | 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 requestAttributes.requestCompleted(); 39 } 40 logResult(request, response, failureCause, asyncManager); 41 publishRequestHandledEvent(request, response, startTime, failureCause); 42 } 43 }
这里交给了doService方法处理:
1 /** 2 * Subclasses must implement this method to do the work of request handling, 3 * receiving a centralized callback for GET, POST, PUT and DELETE. 4 * <p>The contract is essentially the same as that for the commonly overridden 5 * {@code doGet} or {@code doPost} methods of HttpServlet. 6 * <p>This class intercepts calls to ensure that exception handling and 7 * event publication takes place. 8 * @param request current HTTP request 9 * @param response current HTTP response 10 * @throws Exception in case of any kind of processing failure 11 * @see javax.servlet.http.HttpServlet#doGet 12 * @see javax.servlet.http.HttpServlet#doPost 13 */ 14 protected abstract void doService(HttpServletRequest request, HttpServletResponse response) 15 throws Exception;
可见,doService是一个抽象方法,具体功能还是要交给它的子类来实现,也就是DispatcherServlet。
至此,问题就简单了,来看看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 logRequest(request); 8 9 // Keep a snapshot of the request attributes in case of an include, 10 // to be able to restore the original attributes after the include. 11 Map<String, Object> attributesSnapshot = null; 12 if (WebUtils.isIncludeRequest(request)) { 13 attributesSnapshot = new HashMap<>(); 14 Enumeration<?> attrNames = request.getAttributeNames(); 15 while (attrNames.hasMoreElements()) { 16 String attrName = (String) attrNames.nextElement(); 17 if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) { 18 attributesSnapshot.put(attrName, request.getAttribute(attrName)); 19 } 20 } 21 } 22 23 // Make framework objects available to handlers and view objects. 24 request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext()); 25 request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); 26 request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); 27 request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource()); 28 29 if (this.flashMapManager != null) { 30 FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response); 31 if (inputFlashMap != null) { 32 request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap)); 33 } 34 request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap()); 35 request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager); 36 } 37 38 try { 39 doDispatch(request, response); 40 } 41 finally { 42 if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { 43 // Restore the original attribute snapshot, in case of an include. 44 if (attributesSnapshot != null) { 45 restoreAttributesAfterInclude(request, attributesSnapshot); 46 } 47 } 48 } 49 }
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 processedRequest = checkMultipart(request); 25 multipartRequestParsed = (processedRequest != request); 26 27 // Determine handler for the current request. 28 mappedHandler = getHandler(processedRequest); 29 if (mappedHandler == null) { 30 noHandlerFound(processedRequest, response); 31 return; 32 } 33 34 // Determine handler adapter for the current request. 35 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); 36 37 // Process last-modified header, if supported by the handler. 38 String method = request.getMethod(); 39 boolean isGet = "GET".equals(method); 40 if (isGet || "HEAD".equals(method)) { 41 long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); 42 if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { 43 return; 44 } 45 } 46 47 if (!mappedHandler.applyPreHandle(processedRequest, response)) { 48 return; 49 } 50 51 // Actually invoke the handler. 52 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); 53 54 if (asyncManager.isConcurrentHandlingStarted()) { 55 return; 56 } 57 58 applyDefaultViewName(processedRequest, mv); 59 mappedHandler.applyPostHandle(processedRequest, response, mv); 60 } 61 catch (Exception ex) { 62 dispatchException = ex; 63 } 64 catch (Throwable err) { 65 // As of 4.3, we're processing Errors thrown from handler methods as well, 66 // making them available for @ExceptionHandler methods and other scenarios. 67 dispatchException = new NestedServletException("Handler dispatch failed", err); 68 } 69 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); 70 } 71 catch (Exception ex) { 72 triggerAfterCompletion(processedRequest, response, mappedHandler, ex); 73 } 74 catch (Throwable err) { 75 triggerAfterCompletion(processedRequest, response, mappedHandler, 76 new NestedServletException("Handler processing failed", err)); 77 } 78 finally { 79 if (asyncManager.isConcurrentHandlingStarted()) { 80 // Instead of postHandle and afterCompletion 81 if (mappedHandler != null) { 82 mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); 83 } 84 } 85 else { 86 // Clean up any resources used by a multipart request. 87 if (multipartRequestParsed) { 88 cleanupMultipart(processedRequest); 89 } 90 } 91 } 92 }
最终,客户端请求被doService方法交给了doDispatch方法处理,而具体到第52行,交给了一个Handler来处理。
关于这个Handler(RequestMappingHandlerAdapter)的处理流程,它是怎样通过反射机制,把请求最终传递给Controller的,以后有时间再分析。