spring mvc讀書筆記HttpServletBean,FrameworkServlet和DispathcerServlet,doDispatch結構

 

首先,HttpServletBean,FrameworkServlet和DispathcerServlet這三個Servlet的處理過程,最後分析springmvc中最重要的doDispatch方法

 

httpServletBean

主要參與建立工做,並無涉及到請求的處理。web

FrameworkServlet

servlet的處理過程:首先是從servlet接口的service方法開始,而後在HttpServlet的service方法中根據請求的類型不一樣將請求路由到doget,doHead,doPost,doPut,doDelete,doOptionsdoTrace七個方法。而且作了doHead,doOptions,doTrace的默認實現,其中doHead調用doGet,而後返回只有header沒有bodyresponse.spring

在FrameworkServ;et中重寫了service,doGet,doPost,doPut,doDelte,doOptioms,doTrace方法(除了doHead全部處理請求的方法).在service中增長了對patch類型請求的處理,其餘類型的請求直接交給了父類處理;doOptions和doTrace方法能夠經過設置dispatchOptionsRequest和dispatchTraceRequest參數決定是本身處理仍是交給父類處理;doGet,doPost,doPut,doDelete都是本身處理。全部須要本身處理的請求都交給了processRequest方法統一處理。瀏覽器

@Override緩存

         protected void service(HttpServletRequest request, HttpServletResponse response)服務器

                            throws ServletException, IOException {session

                   String method = request.getMethod();mvc

                   if (method.equalsIgnoreCase(RequestMethod.PATCH.name())) {app

                            processRequest(request, response);異步

                   }async

                   else {

                            super.service(request, response);

                   }

         }

 

         protected final void doGet(HttpServletRequest request, HttpServletResponse response)

                            throws ServletException, IOException {

 

                   processRequest(request, response);

         }

這裏所作的事情和HttpServlet中對請求按類型分別進行處理不一樣,這裏正好相反,將全部請求都合併到了processRequest方法,全部請求類型都執行相同的模板方法processRequest.後面將會對不一樣的請求交給不一樣的Handler進行處理。這裏的service不是直接覆蓋HttpServlet中的service方法,而是又將調用super.service(),若是直接用processRequest處理,咱們在作一些特殊的需求在Post請求處理前對request作一些處理,這時可能會新建一個繼承自DispatcherServlet的類,而後覆蓋doPost方法,在裏面先對request作處理,而後在電泳supper.doPost(),這時就會出現問題了。

 

   processRequestFrameworkServlet類在處理請求中最核心的方法

 

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);

                   }

         }

 

         processRequest方法中最核心的語句是doService(request,response),這是一個模板方法,在DispatcherServlet中具體實現。在doService先後還作了一些事情(裝飾模式),先開始從LocaleContextHolder中取得LocaleContext並設置到previousLocalContext,從requestContextHolder中得到RequestAttributes並設置到perviousAttributes,而後調用buildLocaleContext和BuildRequestAttributes方法得到當前請求的LocaleContext和RequestAttributes,經過initContextHolders方法將現有屬性設置到LocaleContextHolderRequestContextHolder中(處理完成後再恢復到原來的值),

   LocaleContext和RequestAttributes是什麼,localeContext裏面存放着Locale(本地信息化 zh-cn等),RequestAttributes是spring的一個接口,經過它能夠get/set/removeAttribute,根據scope參數判斷是request仍是session.這裏具體使用ServletRequestAttribute類,裏面封裝了request,response,session,均可以直接得到。

  // org.springframework.web.context.request.ServletRequestAttributes.class

public void setAttribute(String name, Object value, int scope) {

                   if (scope == SCOPE_REQUEST) {

                            if (!isRequestActive()) {

                                     throw new IllegalStateException(

                                                        "Cannot set request attribute - request is not active anymore!");

                            }

                            this.request.setAttribute(name, value);

                   }

                   else {

                            HttpSession session = getSession(true);

                            this.sessionAttributesToUpdate.remove(name);

                            session.setAttribute(name, value);

                   }

         }

 

 經過scope判斷是對request仍是session進行操做;是直接對request和session進行操做,判斷request是否已經被使用過,isRequestActive(),當requestCompleted以後requestActive就會變爲false,request未完成以前爲true. RequestAttributes用來管理request和session的屬性。

 

org.springframework.context.i18n.LocaleContextHolder.class

LocaleContextHolder是一個抽象類,其中全部的屬性和方法都是static的,能夠直接調用,沒有父類和子類,不能實例化。

private static final ThreadLocal<LocaleContext> localeContextHolder =

                            new NamedThreadLocal<LocaleContext>("Locale context");

 

         private static final ThreadLocal<LocaleContext> inheritableLocaleContextHolder =

                            new NamedInheritableThreadLocal<LocaleContext>("Locale context");

上面兩個屬性都是ThreadLocal<LocaleContext>類型的,LocaleContextHolder中提供了get/set localeContext和Locale方法,好比在程序中要用到Locale的時候,首先是request.getLocale(),這是最直接的方法,若是service層要用到locale時,這時沒有request,能夠在controller中拿出來再傳到service中,這樣也能夠,可是還有一種方法就是用LocaleContextHolder.getLocale();

 

org.springframework.web.context.request.RequestContextHolder.class也是一個抽象的類,裏面的屬性和方法都是static的:

private static final ThreadLocal<RequestAttributes> requestAttributesHolder =

                            new NamedThreadLocal<RequestAttributes>("Request attributes");

         private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder =

                            new NamedInheritableThreadLocal<RequestAttributes>("Request context");

這兩個屬性都是ThreadLocal<RequestAttributes>類型的,其中的方法都是對requestAttribute的set/get/reset/currentRequestAttribute/faces.還包含了一個內部類FacesRequestAttributesFactory,避免硬編碼。

  FrameworkServlet中processRequest中最後finally中對request的屬性進行了恢復調用resetContextHolder方法將原來的localeContext和requestAttribues恢復。緣由是可能在servlet外還有別的操做,爲了避免影響操做,因此須要進行恢復。

 

  最後是publishRequesthandledEvent(request,response,startTime,failureCanse)發佈了消息

org.springframework.web.servlet.FrameworkServlet.class

         private void publishRequestHandledEvent(

                            HttpServletRequest request, HttpServletResponse response, long startTime, Throwable failureCause) {

                   if (this.publishEvents) {

                            // Whether or not we succeeded, publish an event.

                            long processingTime = System.currentTimeMillis() - startTime;

                            int statusCode = (responseGetStatusAvailable ? response.getStatus() : -1);

                            this.webApplicationContext.publishEvent(

                                               new ServletRequestHandledEvent(this,

                                                                 request.getRequestURI(), request.getRemoteAddr(),

                                                                 request.getMethod(), getServletConfig().getServletName(),

                                                                 WebUtils.getSessionId(request), getUsernameForRequest(request),

                                                                 processingTime, failureCause, statusCode));

                   }

         }

 

當publishEvents設置爲true時,就會發布這個消息,不管請求處理成功與否都會發布。

publishEvents能夠在web.xml中配置spring mvc的servlet的時候進行配置,默認爲true,咱們能夠監聽這個事件來作一些事情,如記錄日誌。

 

public class ServletRequestHandledEventListener implements ApplicationListener<ServletRequestHandledEvent> {

         final static Logger logger = LoggerFactory.getLogger("RequestProcessLog");

         @Override

         public void onApplicationEvent(ServletRequestHandledEvent event) {

                   logger.info(event.getDescription());

 

         }

}

 

上面是一個簡單的應用,只要簡單的繼承ApplicationListener,實現對應的方法,而後註冊到spring中就可使用了。

 

   到如今爲止FrameworkServlet就分析完了,回顧一下:首先在service方法中添加了Patch的處理,並將全部須要本身處理的請求都集中到processRequest方法中統一處理,這和HttpServlet裏面根據request的類型將請求分配到各個不一樣的方法裏處理過程正好相反。

 

  而後就是processRequest方法,將主要的處理邏輯交給了doService,這是一個模板方法,在子類中具體實現;另外就是對當前request中得到的LocaleContext和RequestAttributes方法進行保存,以及處理完以後恢復,最後發佈了ServletRequestHandledEvent事件。

 

 

DispatcherServlet

DispatcherServlet是Spring mvc中最核心的類,整個處理過程的頂層設計都在這裏。

DispatcherServlet裏面執行處理的入口方法是doService,不過doService沒有直接處理,而是交給了doDispatch進行具體處理。在doDispatcher處理前doService作了一些事情,首先判斷請求是否是include請求,若是是則對request的Attribute作快照備份,等doDispatch處理完成後進行還原,作完快照後對request設置一些屬性。

org.springframework.web.servlet.DispatcherServlet.class

 

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.

                   //快照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.

                   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));

                   }

                   request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());

                   request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);

                   //交給dodispatch方法

                   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);

                                     }

                            }

                   }

         }

 

對request設置的屬性中,webApplicationContext,lcaoleResolver,ThemeResolver和themeSource後面三個都和flashMap相關,主要用於Redirect轉發時參數的傳遞。好比,爲了不重複提交表單,能夠在處理完post請求後redirect到一個get請求,這樣即便用戶刷新也不會重複提交。這裏有一個問題,提交訂單時有參數,提交完成後redirect到一個顯示訂單的頁面,顯然在顯示訂單的時候還要知道一些參數。按普通的模式若是想要提交參數,就只能將其寫入url中,可是url也有長度限制。另一些場景中咱們不想將參數暴露到url中,這時既能夠用flashMap來進行傳遞參數。只須要將須要傳遞的參數寫入OUTPUT_FLASH_MAP_ATTRIBUTE,例如

 

((FlashMap)((ServletRequestAttributes)(RequestContextHolder.getRequestAttributes())).getRequest().getAttribute(DispatcherServlet.OUTPUT_FLASH_MAP_ATTRIBUTE)).put("name", "張三丰");

 

 這樣在redirect以後的handle中的spring 就會自動將其值設置到model裏,spring還給咱們提供了更加簡單的操做方法,只須要在handler方法的參數中定義redirectAttributes類型的變量,而後將須要保存的屬性設置到裏面就行,以後的事情由spring自動完成.RedirectAttributes有兩種設置參數的方法addAttribute(key,value)addFlashAttribute(key,value),用第一個方法設置的參數會拼接到url中,第二個設置的參數會保存在flashMap中.

@RequestMapping(value="/submit",method=RequestMethod.POST)

         public String submit(RedirectAttributes attr) throws IOException{

                   ((FlashMap) ((ServletRequestAttributes) (RequestContextHolder.getRequestAttributes())).getRequest()

                                     .getAttribute(DispatcherServlet.OUTPUT_FLASH_MAP_ATTRIBUTE)).put("name", "張三丰");

                   attr.addAttribute("orderId","one");

                   attr.addFlashAttribute("local","zh-cn");

                   return "redirect:showorders";

                  

         }

         @RequestMapping(value="/showorders",method=RequestMethod.GET)

         public String showOrders(Model model) throws IOException{

                   //dothing....

                   return "orders";

         }

這裏分別用三種方法傳輸redirect參數

1.RequestContextHolder得到request,並從中拿到outputflashMao,將屬性放進去;

2.RedirectAttributes中addFlashAttribute方法設置

3,經過RedirectAttributes中的addAttribute方法設置,這樣設置參數不會保存到flashMao中,而是拼接到url中;

  還能夠用requestContextUtils來操做:RequestContextUtils.getOutoutFlashNap(request),這樣能夠獲得outputFlashMap,其內部仍是從Request的屬性中得到的。

這就是flashMap的用法,inputFlashMap用於保存上次請求中轉發過來的屬性,outputFlashMap用來保存本次請求須要轉發的屬性,FlashMapManager用於管理他們;

 

doService對request設置了一些屬性,若是是include屬性,會對request當前的屬性進行快照備份,並在處理結束後恢復,最後將請求轉發給doDispatch方法。

 

doDispatch方法很是簡潔,從頂層設計了整個請求處理的過程,doDispatch只有四句核心的代碼,他們的任務分別是:1.根據request找到Handler;2根據handler找到對應的HandlerAdaper;3.用HandlerAdaper處理Handler;4.調用processDispatchResult方法處理上面的結果(包含找到view並渲染輸出給用戶),

 

mappedHandler = getHandler(processedRequest);

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

 

上面有三個須要瞭解的地方:HandlerMapping,Handler,HandlerAdapter,下面具體說一下:

 

HandlerMapping:查找請求對應的Handler,有許多請求,每一個請求都須要一個handler來處理,具體接收到請求後用哪一個handler來處理呢,這就是handlerMapping要作的事情。

 

HandlerAdapter:從名字上看它是一個適配器,spring mvc中handler能夠是任意類型,只要能處理請求就夠了,可是servlet中的處理方法的結構倒是固定的,都是以request和response做爲參數的(例如doService方法),如何讓固定格式的servlet處理方法調用靈活的handler來處理呢?這就是HandlerAdapter要作的事。

 

Handler是用來幹活的工具,HandlerMapping是用於根據須要乾的活找到對應的工具,HandlerAdapter是用工具幹活的人。

 

view 和viewResolver的原理與handler和HandlerMapping 的原理相似。view是用來展示model的數據的,而viewResolver是用來查找view的。

 

   上面四句代碼就是handlerMapping找到幹活的handler,找到使用handler的HandlerAdapter,讓HandlerAdapter使用handler幹活,幹完活後將結果寫個報告(經過view展示)

 

doDospatch結構

org.springframework.web.servlet.DispatcherServlet.class

         protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {

                   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);

 

                                     // Determine handler for the current request.

                                     //當前請求的處理器

                                     mappedHandler = getHandler(processedRequest);

                                     if (mappedHandler == null || mappedHandler.getHandler() == null) {

                                               noHandlerFound(processedRequest, response);

                                               return;

                                     }

 

                                     // Determine handler adapter for the current request.

//當前請求的處理適配器

                                     HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

 

                                     // Process last-modified header, if supported by the handler.

                                     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;

                                               }

                                     }

 

                                     if (!mappedHandler.applyPreHandle(processedRequest, response)) {

                                               return;

                                     }

 

                                     // Actually invoke the handler.

                                     //調用處理請求

                                     mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

 

                                     //若是異步,直接返回

if (asyncManager.isConcurrentHandlingStarted()) {

                                               return;

                                     }

 

                                     applyDefaultViewName(request, mv);

                                     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);

                                     }

                            }

                   }

         }

 

doDispatch大致分爲兩部分:處理請求和渲染頁面

 

HttpServletRequest processedRequest:實際處理時所用到的request,若是不是上傳請求則直接使用接收到的request,不然封裝爲上傳類型的request;

 

HandlerExceptionChain mappedHandler:處理請求時的處理器鏈(包含處理器和對應的Interceptor)

 

Boolean multipartRequestParsed:是否是上傳請求的標識

 

ModelAndView mv:封裝model和view的容器。此變量在整個springmvc中承擔着很是重要的角色。

 

Exception dispatchException:處理請求過程當中拋出的異常,它不包含渲染過程拋出的異常。

 

doDispatch中首先檢查是否是上傳請求,若是是上傳請求,就將request轉換爲MultipartHttpServletrequest,並將mulitipartRequestParsed標識設置爲true,其中也用到了multipartResolver.

 

  而後經過gethandler方法得到處理器鏈,其中使用到了handlerMapping,返回值類型爲handlerExecutionChain類型,其中包含着與當前request相匹配的Interceptor和Handler,

 

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {

                   for (HandlerMapping hm : this.handlerMappings) {

                            if (logger.isTraceEnabled()) {

                                     logger.trace(

                                                        "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");

                            }

                            HandlerExecutionChain handler = hm.getHandler(request);

                            if (handler != null) {

                                     return handler;

                            }

                   }

                   return null;

         }

 

  接下來是處理get,head請求的last_modified,當瀏覽器第一次跟服務器請求資源(get,head請求)時,服務器在返回的請求頭裏會包含一個Last_modified的屬性,表明本資源最後是何時修改的,在瀏覽器之後發送請求的時候會同時發送以前接收到的last_modifed,服務器接收到帶last_modified的請求後會用其值和本身的實際資源的最後修改時間作對比,若是資源過時了則返回新的資源(同時返回新的last-modified),不然直接返回304狀態碼錶示資源未過時,瀏覽器也直接使用以前緩存的結果。

 

接下來調用相應Interceptor的preHandle.

 

處理完Interceptor的preHandle後就到了處理請求的關鍵地方-讓handleAdapter使用handler處理請求,Controller就是在這個地方執行的,這裏主要使用了handlerAdapter.

 

handler處理完成後,若是須要異步請求,則直接返回,若是不須要,當view爲空時,設置爲默認view,而後執行相應的Interceptor的postHandle,設置默認view的過程當中使用到了ViewNameTranslator..

 

到這裏請求的內容完成了,接下來使用processDispatchResult方法處理前面返回的結果,其中包含處理異常,內部異常處理和自己拋出的異常。

 

         private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,

                            HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {

 

                   boolean errorView = false;

 

                   if (exception != null) {

                            if (exception instanceof ModelAndViewDefiningException) {

                                     logger.debug("ModelAndViewDefiningException encountered", exception);

                                     mv = ((ModelAndViewDefiningException) exception).getModelAndView();

                            }

                            else {

                                     Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);

                                     mv = processHandlerException(request, response, handler, exception);

                                     errorView = (mv != null);

                            }

                   }

 

                   // Did the handler return a view to render?

                   if (mv != null && !mv.wasCleared()) {

                            render(mv, request, response);

                            if (errorView) {

                                     WebUtils.clearErrorRequestAttributes(request);

                            }

                   }

                   else {

                            if (logger.isDebugEnabled()) {

                                     logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +

                                                        "': assuming HandlerAdapter completed request handling");

                            }

                   }

 

                   if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {

                            // Concurrent handling started during a forward

                            return;

                   }

 

                   if (mappedHandler != null) {

                            mappedHandler.triggerAfterCompletion(request, response, null);

                   }

         }

 

以下是doDispatch的流程圖:

 

總結

 三個Servlet處理中的大體功能:

HttpServletBean:沒有參與實踐請求的處理;

FrameworkServlet:將不一樣類型的請求合併到了processRequest方法統一處理

 processRequest作了三件事:

  調用了doService模板方法具體處理請求;

 

  將當前請求的LocaleContext和ServletRequestAttributes在處理請求前設置到LocaleContextHolder和RequestContextHolder,並在請求處理完成後恢復;

 請求處理完成後發佈ServletRequestHandledEvent消息。

 

DispatcherServlet:doSerivce方法給request設置了一些屬性,並將請求交給了doDispatch方法具體處理。

DispatcherServlet中的doDispatch方法完成了Spring mvc中請求處理過程的頂層設計,使用了DIspatcherSerlvet中的九大組件完成了具體的請求處理。

相關文章
相關標籤/搜索