在之前的博客 springMVC源碼分析--容器初始化(二)DispatcherServlet中我們介紹過DispatcherServlet,是在容器初始化過程中出現的,我們之前也說過DispatcherServlet其實就是一個HttpServlet,其實他是HttpServlet的子類,所以它和普通的HttpServlet有同樣的配置:
- <span style="font-size:14px;"><span style="white-space:pre"> </span><servlet>
- <servlet-name>springmvc</servlet-name>
- <servlet-class>
- org.springframework.web.servlet.DispatcherServlet
- </servlet-class>
- <init-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>classpath:springmvc-config.xml</param-value>
- </init-param>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>springmvc</servlet-name>
- <url-pattern>*.action</url-pattern>
- </servlet-mapping></span>
既然DispatcherServlet是一個HttpServlet那麼它應該會實現HttpServlet提供的如下方法:
當然這些所有的方法的實現是DispatcherServlet的父類FrameworkServlet中實現的。
當然這些實現方法中的默認實現其實是如下的
FrameworkServlet類中
- @Override
- protected final void doPost(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- processRequest(request, response);
- }
- @Override
- protected final void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- processRequest(request, response);
- }
- protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- long startTime = System.currentTimeMillis();
- Throwable failureCause = null;
- LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
- LocaleContext localeContext = buildLocaleContext(request);
- RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
- ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
- WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
- asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
- initContextHolders(request, localeContext, requestAttributes);
- try {
- doService(request, response);
- }
- catch (ServletException ex) {
- failureCause = ex;
- throw ex;
- }
- catch (IOException ex) {
- failureCause = ex;
- throw ex;
- }
- catch (Throwable ex) {
- failureCause = ex;
- throw new NestedServletException("Request processing failed", ex);
- }
- finally {
- resetContextHolders(request, previousLocaleContext, previousAttributes);
- if (requestAttributes != null) {
- requestAttributes.requestCompleted();
- }
- if (logger.isDebugEnabled()) {
- if (failureCause != null) {
- this.logger.debug("Could not complete request", failureCause);
- }
- else {
- if (asyncManager.isConcurrentHandlingStarted()) {
- logger.debug("Leaving response open for concurrent processing");
- }
- else {
- this.logger.debug("Successfully completed request");
- }
- }
- }
- publishRequestHandledEvent(request, response, startTime, failureCause);
- }
- }
doService方法的最終實現是在DispatcherServlet中,這樣所有的Http請求(GET、POST、PUT和DELETE等)的最終操作就DispatcherServlet中實現了。
DispatcherServlet中doService的實現如下,對Request設置了一些全局屬性,最終接下來的操作是在doDispatcher函數中實現了。
- //獲取請求,設置一些request的參數,然後分發給doDispatch
- @Override
- protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
- if (logger.isDebugEnabled()) {
- String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
- logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
- " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
- }
- // Keep a snapshot of the request attributes in case of an include,
- // to be able to restore the original attributes after the include.
- Map<String, Object> attributesSnapshot = null;
- if (WebUtils.isIncludeRequest(request)) {
- attributesSnapshot = new HashMap<String, Object>();
- Enumeration<?> attrNames = request.getAttributeNames();
- while (attrNames.hasMoreElements()) {
- String attrName = (String) attrNames.nextElement();
- if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
- attributesSnapshot.put(attrName, request.getAttribute(attrName));
- }
- }
- }
- // Make framework objects available to handlers and view objects.
- /* 設置web應用上下文**/
- request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
- /* 國際化本地**/
- request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
- /* 樣式**/
- request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
- //設置樣式資源
- request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
- //請求刷新時保存屬性
- FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
- if (inputFlashMap != null) {
- request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
- }
- //Flash attributes 在對請求的重定向生效之前被臨時存儲(通常是在session)中,並且在重定向之後被立即移除
- request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
- //FlashMap 被用來管理 flash attributes 而 FlashMapManager 則被用來存儲,獲取和管理 FlashMap 實體.
- request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
- try {
- doDispatch(request, response);
- }
- finally {
- if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
- // Restore the original attribute snapshot, in case of an include.
- if (attributesSnapshot != null) {
- restoreAttributesAfterInclude(request, attributesSnapshot);
- }
- }
- }
- }
- /**
- *將Handler進行分發,handler會被handlerMapping有序的獲得
- *通過查詢servlet安裝的HandlerAdapters來獲得HandlerAdapters來查找第一個支持handler的類
- *所有的HTTP的方法都會被這個方法掌控。取決於HandlerAdapters 或者handlers 他們自己去決定哪些方法是可用
- *@param request current HTTP request
- *@param response current HTTP response
- */
- protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
- /* 當前HTTP請求**/
- HttpServletRequest processedRequest = request;
- HandlerExecutionChain mappedHandler = null;
- boolean multipartRequestParsed = false;
- WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
- try {
- ModelAndView mv = null;
- Exception dispatchException = null;
- try {
- //判斷是否有文件上傳
- processedRequest = checkMultipart(request);
- multipartRequestParsed = (processedRequest != request);
- // 獲得HandlerExecutionChain,其包含HandlerIntercrptor和HandlerMethod
- mappedHandler = getHandler(processedRequest);
- if (mappedHandler == null || mappedHandler.getHandler() == null) {
- noHandlerFound(processedRequest, response);
- return;
- }
- //獲得HandlerAdapter
- HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
- //獲得HTTP請求方法
- String method = request.getMethod();
- boolean isGet = "GET".equals(method);
- if (isGet || "HEAD".equals(method)) {
- long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
- if (logger.isDebugEnabled()) {
- logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
- }
- if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
- return;
- }
- }
- //如果有攔截器的話,會執行攔截器的preHandler方法
- if (!mappedHandler.applyPreHandle(processedRequest, response)) {
- return;
- }
- //返回ModelAndView
- mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
- if (asyncManager.isConcurrentHandlingStarted()) {
- return;
- }
- //當view爲空時,,根據request設置默認view
- applyDefaultViewName(processedRequest, mv);
- //執行攔截器的postHandle
- mappedHandler.applyPostHandle(processedRequest, response, mv);
- }
- catch (Exception ex) {
- dispatchException = ex;
- }
- processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
- }
- catch (Exception ex) {
- triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
- }
- catch (Error err) {
- triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
- }
- finally {
- //判斷是否是異步請求
- if (asyncManager.isConcurrentHandlingStarted()) {
- // Instead of postHandle and afterCompletion
- if (mappedHandler != null) {
- mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
- }
- }
- else {
- // Clean up any resources used by a multipart request.
- //刪除上傳資源
- if (multipartRequestParsed) {
- cleanupMultipart(processedRequest);
- }
- }
- }
- }