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的,以后有时间再分析。

 

posted @ 2018-11-19 17:02  空の彼方  阅读(834)  评论(0编辑  收藏  举报