天天看點

java前端控制器如何處理請求_Spring MVC源碼(二) ----- DispatcherServlet 請求處理流程 面試必問...

前端控制器

前端控制器,即所謂的Front Controller,展現的是設計模式中的前端控制器模式。前端控制器處理所有從使用者過來的請求。所有使用者的請求都要通過前端控制器。SpringMVC架構和其他請求驅動的表示層架構一樣,也是圍繞一個将請求分發到相應控制器的核心Servlet來設計的。DispatcherServlet和其他架構中的Servlet不一樣的地方在于,它和Spring容器無縫整合在了一起,是以你可以在SpringMVC中使用Spring容器所有的特性。

DispatcherServlet這個前端控制器,在SpringMVC中的作用,以官方文檔中的配圖來說明:

java前端控制器如何處理請求_Spring MVC源碼(二) ----- DispatcherServlet 請求處理流程 面試必問...

整個流程可以被大緻描述為:一個http請求到達伺服器,被DispatcherServlet接收。DispatcherServlet将請求委派給合适的處理器Controller,此時處理控制權到達Controller對象。Controller内部完成請求的資料模型的建立和業務邏輯的處理,然後再将填充了資料後的模型即model和控制權一并交還給DispatcherServlet,委派DispatcherServlet來渲染響應。DispatcherServlet再将這些資料和适當的資料模版視圖結合,向Response輸出響應。

DispatcherServlet

SpringMVC完成初始化流程之後,就進入Servlet标準生命周期的第二個階段,即“service”階段。在“service”階段中,每一次Http請求到來,容器都會啟動一個請求線程,通過service()方法,委派到doGet()或者doPost()這些方法,完成Http請求的處理。

在初始化流程中,SpringMVC巧妙的運用依賴注入讀取參數,并最終建立一個與容器上下文相關聯的Spring子上下文。這個子上下文,就像Struts2中xwork容器一樣,為接下來的Http處理流程中各種程式設計元素提供了容身之所。如果說将Spring上下文關聯到Servlet容器中,是SpringMVC架構的第一個亮點,那麼在請求轉發流程中,SpringMVC對各種處理環節程式設計元素的抽象,就是另外一個獨具匠心的亮點。

Struts2采取的是一種完全和Web容器隔離和解耦的事件機制。諸如Action對象、Result對象、Interceptor對象,這些都是完全脫離Servlet容器的程式設計元素。Struts2将資料流和事件處理完全剝離開來,從Http請求中讀取資料後,下面的事件處理流程就隻依賴于這些資料,而完全不知道有Web環境的存在。

反觀SpringMVC,無論HandlerMapping對象、HandlerAdapter對象還是View對象,這些核心的接口所定義的方法中,HttpServletRequest和HttpServletResponse對象都是直接作為方法的參數出現的。這也就意味着,架構的設計者,直接将SpringMVC架構和容器綁定到了一起。或者說,整個SpringMVC架構,都是依托着Servlet容器元素來設計的。下面就來看一下,源碼中是如何展現這一點的。

請求轉發的入口

就像任何一個注冊在容器中的Servlet一樣,DispatcherServlet也是通過自己的service()方法來接收和轉發Http請求到具體的doGet()或doPost()這些方法的。以一次典型的GET請求為例,經過HttpServlet基類中service()方法的委派,請求會被轉發到doGet()方法或者doPost()方法中。

protected voidservice(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

String method=req.getMethod();longlastModified;if (method.equals("GET")) {

lastModified= this.getLastModified(req);if (lastModified == -1L) {this.doGet(req, resp);

}else{long ifModifiedSince = req.getDateHeader("If-Modified-Since");if (ifModifiedSince

}else{

resp.setStatus(304);

}

}

}else if (method.equals("HEAD")) {

lastModified= this.getLastModified(req);this.maybeSetLastModified(resp, lastModified);this.doHead(req, resp);

}else if (method.equals("POST")) {this.doPost(req, resp);

}else if (method.equals("PUT")) {this.doPut(req, resp);

}else if (method.equals("DELETE")) {this.doDelete(req, resp);

}else if (method.equals("OPTIONS")) {this.doOptions(req, resp);

}else if (method.equals("TRACE")) {this.doTrace(req, resp);

}else{

String errMsg= lStrings.getString("http.method_not_implemented");

Object[] errArgs= newObject[]{method};

errMsg=MessageFormat.format(errMsg, errArgs);

resp.sendError(501, errMsg);

}

}

doGet() 和 doPost() 方法,在DispatcherServlet的父類FrameworkServlet類中被覆寫。

protected final voiddoGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.processRequest(request, response);

}protected final voiddoPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.processRequest(request, response);

}

可以看到,這裡隻是簡單的轉發到processRequest()這個方法。

protected final voidprocessRequest(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {long startTime =System.currentTimeMillis();

Throwable failureCause= null;//Expose current LocaleResolver and request as LocaleContext.

LocaleContext previousLocaleContext =LocaleContextHolder.getLocaleContext();

LocaleContextHolder.setLocaleContext(buildLocaleContext(request),this.threadContextInheritable);//Expose current RequestAttributes to current thread.

RequestAttributes previousRequestAttributes =RequestContextHolder.getRequestAttributes();

ServletRequestAttributes requestAttributes= null;if (previousRequestAttributes == null || previousRequestAttributes.getClass().equals(ServletRequestAttributes.class)) {

requestAttributes= newServletRequestAttributes(request);

RequestContextHolder.setRequestAttributes(requestAttributes,this.threadContextInheritable);

}if(logger.isTraceEnabled()) {

logger.trace("Bound request context to thread:" +request);

}try{

doService(request, response);

}finally{//Clear request attributes and reset thread-bound context.

LocaleContextHolder.setLocaleContext(previousLocaleContext, this.threadContextInheritable);if (requestAttributes != null) {

RequestContextHolder.setRequestAttributes(previousRequestAttributes,this.threadContextInheritable);

requestAttributes.requestCompleted();

}if (this.publishEvents) {//Whether or not we succeeded, publish an event.

long processingTime = System.currentTimeMillis() -startTime;this.webApplicationContext.publishEvent(new ServletRequestHandledEvent(this,

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

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

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

processingTime, failureCause));

}

}

}

可以看到,processRequest()方法隻是做了一些線程安全的隔離,真正的請求處理,發生在doService()方法中。點開FrameworkServlet類中的doService()方法。

protected abstract voiddoService(HttpServletRequest request, HttpServletResponse response)

throws Exception;

又是一個抽象方法,這也是SpringMVC類設計中的慣用伎倆:父類抽象處理流程,子類給予具體的實作。真正的實作是在DispatcherServlet類中。

讓我們接着看DispatcherServlet類中實作的doService()方法。

@Overrideprotected voiddoService(HttpServletRequest request, HttpServletResponse response) throws Exception {if(logger.isDebugEnabled()) {

String requestUri=urlPathHelper.getRequestUri(request);

logger.debug("DispatcherServlet with name '" + getServletName() + "' processing" + request.getMethod() +

"request for [" + requestUri + "]");

}//Keep a snapshot of the request attributes in case of an include,//to be able to restore the original attributes after the include.

Map attributesSnapshot = null;if(WebUtils.isIncludeRequest(request)) {

logger.debug("Taking snapshot of request attributes before include");

attributesSnapshot= new HashMap();

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,newFlashMap());

request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE,this.flashMapManager);try{

doDispatch(request, response);

}finally{//Restore the original attribute snapshot, in case of an include.

if (attributesSnapshot != null) {

restoreAttributesAfterInclude(request, attributesSnapshot);

}

}

}

幾個requet.setAttribute()方法的調用,将前面在初始化流程中執行個體化的對象設定到http請求的屬性中,供下一步處理使用,其中有容器的上下文對象、本地化解析器等SpringMVC特有的程式設計元素。不同于Struts2中的ValueStack,SpringMVC的資料并沒有從HttpServletRequest對象中抽離出來再存進另外一個程式設計元素,這也跟SpringMVC的設計思想有關。因為從一開始,SpringMVC的設計者就認為,不應該将請求處理過程和Web容器完全隔離。

是以,你可以看到,真正發生請求轉發的方法doDispatch()中,它的參數是HttpServletRequest和HttpServletResponse對象。這給我們傳遞的意思也很明确,從request中能擷取到一切請求的資料,從response中,我們又可以往伺服器端輸出任何響應,Http請求的處理,就應該圍繞這兩個對象來設計。我們不妨可以将SpringMVC這種設計方案,是從Struts2的過度設計中吸取教訓,而向Servlet程式設計的一種回歸和簡化。

而對請求的處理交給doDispatcher方法

protected voiddoDispatch(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);//決定目前請求的Handler

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

noHandlerFound(processedRequest, response);return;

}//決定目前請求的HandlerAdapter

HandlerAdapter ha =getHandlerAdapter(mappedHandler.getHandler());//處理last-modified請求頭

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;

}//Handler實際執行請求

mv =ha.handle(processedRequest, response, mappedHandler.getHandler());if(asyncManager.isConcurrentHandlingStarted()) {return;

}//設定預設視圖名

applyDefaultViewName(processedRequest, mv);//攔截器後置處理

mappedHandler.applyPostHandle(processedRequest, response, mv);

}catch(Exception ex) {

dispatchException=ex;

}catch(Throwable err) {//As of 4.3, we're processing Errors thrown from handler methods as well,//making them available for @ExceptionHandler methods and other scenarios.

dispatchException = new NestedServletException("Handler dispatch failed", err);

}//選擇視圖并渲染視圖

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

}catch(Exception ex) {

triggerAfterCompletion(processedRequest, response, mappedHandler, ex);

}catch(Throwable err) {

triggerAfterCompletion(processedRequest, response, mappedHandler,new NestedServletException("Handler processing failed", 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);

}

}

}

}

先看doDispatcher方法執行的主要操作時序圖

java前端控制器如何處理請求_Spring MVC源碼(二) ----- DispatcherServlet 請求處理流程 面試必問...

請求路由

getHandler方法就是從HandlerMapping中查詢比對目前request的Handler。我們看到隻要一比對上 handler 就不再循環,直接傳回

protectedHandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {for (HandlerMapping hm : this.handlerMappings) {

HandlerExecutionChain handler=hm.getHandler(request);if (handler != null) {returnhandler;

}

}return null;

}

HandlerMapping的getHandler方法在抽象基類AbstractHandlerMapping

publicfinal HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {//由子類根據request擷取Handler

Object handler =getHandlerInternal(request);//如果沒比對到,則擷取預設Handler

if (handler == null) {

handler=getDefaultHandler();

}if (handler == null) {return null;

}//如果傳回的Handler為String,則使用Spring容器執行個體化

if(handler instanceof String) {

String handlerName=(String) handler;

handler=getApplicationContext().getBean(handlerName);

}//查詢比對的攔截器,組裝Handler生成HandlerExecutionChain

HandlerExecutionChain executionChain =getHandlerExecutionChain(handler, request);if(CorsUtils.isCorsRequest(request)) {

CorsConfiguration globalConfig= this.corsConfigSource.getCorsConfiguration(request);

CorsConfiguration handlerConfig=getCorsConfiguration(handler, request);

CorsConfiguration config= (globalConfig != null ?globalConfig.combine(handlerConfig) : handlerConfig);

executionChain=getCorsHandlerExecutionChain(request, executionChain, config);

}returnexecutionChain;

}

最終傳回的Handler是由攔截器鍊和Handler共同組成的,而具體比對Handler的方法是交給子類來完成的。上一章元件初始化中提到生産環境下使用的是RequestMappingHandlerMapping,getHandlerInternal方法的實作在它的基類AbstractHandlerMethodMapping。

protectedHandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {//從request擷取比對url

String lookupPath =getUrlPathHelper().getLookupPathForRequest(request);if(logger.isDebugEnabled()) {

logger.debug("Looking up handler method for path" +lookupPath);

}this.mappingRegistry.acquireReadLock();try{//查詢比對的HandlerMethod

HandlerMethod handlerMethod =lookupHandlerMethod(lookupPath, request);if(logger.isDebugEnabled()) {if (handlerMethod != null) {

logger.debug("Returning handler method [" + handlerMethod + "]");

}else{

logger.debug("Did not find handler method for [" + lookupPath + "]");

}

}return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);

}finally{this.mappingRegistry.releaseReadLock();

}

}

可以看到傳回的Handler的類型為HandlerMethod,它對應于Controller中的方法。上一章也提過,在AbstractHandlerMethodMapping中有一個MappingRegistry,統一管理URL和Controller方法的映射關系,lookupHandlerMethod就是對MappingRegistry的操作。

protectedHandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {

List matches = new ArrayList();//從mappingRegistry擷取比對到的RequestMappingInfo

List directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);if (directPathMatches != null) {

addMatchingMappings(directPathMatches, matches, request);

}if(matches.isEmpty()) {//No choice but to go through all mappings...

addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);

}//對比對項進行排序

if (!matches.isEmpty()) {

Comparator comparator = newMatchComparator(getMappingComparator(request));

Collections.sort(matches, comparator);if(logger.isTraceEnabled()) {

logger.trace("Found" + matches.size() + "matching mapping(s) for [" +lookupPath+ "] :" +matches);

}

Match bestMatch= matches.get(0);if (matches.size() > 1) {if(CorsUtils.isPreFlightRequest(request)) {returnPREFLIGHT_AMBIGUOUS_MATCH;

}

Match secondBestMatch= matches.get(1);if (comparator.compare(bestMatch, secondBestMatch) == 0) {

Method m1=bestMatch.handlerMethod.getMethod();

Method m2=secondBestMatch.handlerMethod.getMethod();throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +request.getRequestURL()+ "': {" + m1 + "," + m2 + "}");

}

}

handleMatch(bestMatch.mapping, lookupPath, request);returnbestMatch.handlerMethod;

}else{//無比對項處理

return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);

}

}

通過mappingRegistry比對傳回RequestMappingInfo,對應于每個有@RequestMapping注解解析後的Method。

我們來看看,HandlerExecutionChain類的代碼。

package org.springframework.web.servlet;

import java.util.ArrayList;

import java.util.Arrays;

import java.util.List;

import org.springframework.util.CollectionUtils;public classHandlerExecutionChain {privatefinal Object handler;privateHandlerInterceptor[] interceptors;private ListinterceptorList;publicHandlerExecutionChain(Object handler) {this(handler, null);

}publicHandlerExecutionChain(Object handler, HandlerInterceptor[] interceptors) {if(handler instanceof HandlerExecutionChain) {

HandlerExecutionChain originalChain=(HandlerExecutionChain) handler;this.handler =originalChain.getHandler();this.interceptorList = new ArrayList();

CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(),this.interceptorList);

CollectionUtils.mergeArrayIntoCollection(interceptors,this.interceptorList);

}else{this.handler =handler;this.interceptors =interceptors;

}

}publicObject getHandler() {return this.handler;

}public voidaddInterceptor(HandlerInterceptor interceptor) {

initInterceptorList();this.interceptorList.add(interceptor);

}public voidaddInterceptors(HandlerInterceptor[] interceptors) {if (interceptors != null) {

initInterceptorList();this.interceptorList.addAll(Arrays.asList(interceptors));

}

}private voidinitInterceptorList() {if (this.interceptorList == null) {this.interceptorList = new ArrayList();

}if (this.interceptors != null) {this.interceptorList.addAll(Arrays.asList(this.interceptors));this.interceptors = null;

}

}publicHandlerInterceptor[] getInterceptors() {if (this.interceptors == null && this.interceptorList != null) {this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[this.interceptorList.size()]);

}return this.interceptors;

}

}

一個攔截器清單,一個執行對象,這個類的内容十分的簡單,它蘊含的設計思想,卻十分的豐富。

1.攔截器組成的清單,在執行對象被調用的前後,會依次執行。這裡可以看成是一個的AOP環繞通知,攔截器可以對處理對象随心所欲的進行處理和增強。這裡明顯是吸收了Struts2中攔截器的設計思想。這種AOP環繞式的擴充點設計,也幾乎成為所有架構必備的内容。

2.實際的處理對象,即handler對象,是由Object對象來引用的。

private final Object handler;

當我們拿到HandlerExecutionChain,就完成了request到Controller的路由操作。

擴充卡比對

有了Handler後,需要合适的HandlerAdapter對其進行操作,因而就要根據Handler進行比對。

protectedHandlerAdapter getHandlerAdapter(Object handler) throws ServletException {for (HandlerAdapter ha : this.handlerAdapters) {if(logger.isTraceEnabled()) {

logger.trace("Testing handler adapter [" + ha + "]");

}if(ha.supports(handler)) {returnha;

}

}throw new ServletException("No adapter for handler [" + handler +

"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");

}

HandlerAdapter接口中定義了supports方法,用于檢測是否支援Handler。生産環境使用的RequestMappingHandlerAdapter在其基類AbstractHandlerMethodAdapter中實作了supports方法。

publicfinal boolean supports(Object handler) {return (handler instanceof HandlerMethod &&supportsInternal((HandlerMethod) handler));

}

supportsInternal方法在RequestMappingHandlerAdapter的實作裡預設傳回true。因而RequestMappingHandlerAdapter就是用來支援類型為HandlerMethod的Handler的處理的。

攔截器處理

在SpringMVC中的攔截器接口HandlerInterceptor中定義了三個方法

public interfaceHandlerInterceptor {//在Handler找到後,執行前攔截

boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

throws Exception;//在Handler執行後,視圖渲染前攔截

voidpostHandle(

HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)

throws Exception;//請求處理完成,視圖渲染後執行資源清理等

voidafterCompletion(

HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)

throws Exception;

}

可以很清晰地對應到doDispatcher方法中。需要注意的有幾點

前置處理preHandle,傳回值為boolean。如果傳回true,則執行下一個,如果傳回false,則認為目前攔截器完成了請求,DispatcherServlet會直接傳回,在傳回前會調用所有攔截器的afterCompletion方法,完成清理工作。

afterCompletion方法在遇到任何情況時都需要被執行,無論是成功傳回還是抛出異常。

執行請求

HandlerAdapter的handle方法完成請求的真正執行。在AbstractHandlerMethodAdapter中由handleInternal執行。

protectedModelAndView handleInternal(HttpServletRequest request,

HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

ModelAndView mav;

checkRequest(request);//執行HandlerMethod

mav =invokeHandlerMethod(request, response, handlerMethod);//處理緩存

if (!response.containsHeader(HEADER_CACHE_CONTROL)) {if(getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {

applyCacheSeconds(response,this.cacheSecondsForSessionAttributeHandlers);

}else{

prepareResponse(response);

}

}returnmav;

}

在invokeHandlerMethod中,HandlerMethod被封裝ServletInvocableHandlerMethod,包裹上方法執行需要的資訊。

protectedModelAndView invokeHandlerMethod(HttpServletRequest request,

HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

ServletWebRequest webRequest= newServletWebRequest(request, response);try{

WebDataBinderFactory binderFactory=getDataBinderFactory(handlerMethod);

ModelFactory modelFactory=getModelFactory(handlerMethod, binderFactory);//封裝HandlerMethod

ServletInvocableHandlerMethod invocableMethod =createInvocableHandlerMethod(handlerMethod);

invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);

invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);

invocableMethod.setDataBinderFactory(binderFactory);

invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

ModelAndViewContainer mavContainer= newModelAndViewContainer();

mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));

modelFactory.initModel(webRequest, mavContainer, invocableMethod);

mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);//異步請求處理

AsyncWebRequest asyncWebRequest =WebAsyncUtils.createAsyncWebRequest(request, response);

asyncWebRequest.setTimeout(this.asyncRequestTimeout);

WebAsyncManager asyncManager=WebAsyncUtils.getAsyncManager(request);

asyncManager.setTaskExecutor(this.taskExecutor);

asyncManager.setAsyncWebRequest(asyncWebRequest);

asyncManager.registerCallableInterceptors(this.callableInterceptors);

asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);if(asyncManager.hasConcurrentResult()) {

Object result=asyncManager.getConcurrentResult();

mavContainer= (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];

asyncManager.clearConcurrentResult();if(logger.isDebugEnabled()) {

logger.debug("Found concurrent result value [" + result + "]");

}

invocableMethod=invocableMethod.wrapConcurrentResult(result);

}//執行處理

invocableMethod.invokeAndHandle(webRequest, mavContainer);if(asyncManager.isConcurrentHandlingStarted()) {return null;

}//封裝資料和視圖

returngetModelAndView(mavContainer, modelFactory, webRequest);

}finally{

webRequest.requestCompleted();

}

}

再到ServletInvocableHandlerMethod的invokeAndHandle方法

public voidinvokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,

Object... providedArgs) throws Exception {//執行request

Object returnValue =invokeForRequest(webRequest, mavContainer, providedArgs);

setResponseStatus(webRequest);if (returnValue == null) {if (isRequestNotModified(webRequest) || getResponseStatus() != null ||mavContainer.isRequestHandled()) {

mavContainer.setRequestHandled(true);return;

}

}else if(StringUtils.hasText(getResponseStatusReason())) {

mavContainer.setRequestHandled(true);return;

}

mavContainer.setRequestHandled(false);try{//對傳回值進行處理

this.returnValueHandlers.handleReturnValue(

returnValue, getReturnValueType(returnValue), mavContainer, webRequest);

}catch(Exception ex) {if(logger.isTraceEnabled()) {

logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);

}throwex;

}

}publicObject invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,

Object... providedArgs) throws Exception {//執行方法參數

Object[] args =getMethodArgumentValues(request, mavContainer, providedArgs);if(logger.isTraceEnabled()) {

logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +

"' with arguments" +Arrays.toString(args));

}

Object returnValue=doInvoke(args);if(logger.isTraceEnabled()) {

logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +

"] returned [" + returnValue + "]");

}returnreturnValue;

}protectedObject doInvoke(Object... args) throws Exception {

ReflectionUtils.makeAccessible(getBridgedMethod());returngetBridgedMethod().invoke(getBean(), args);

}

java前端控制器如何處理請求_Spring MVC源碼(二) ----- DispatcherServlet 請求處理流程 面試必問...

需要說明的一點是方法執行完成的傳回值通過傳回值處理器HandlerMethodReturnValueHandler進行處理。在RequestMappingHandlerAdapter的初始化中,内置了衆多的HandlerMethodReturnValueHandler來處理多種類型的傳回值。

在完成請求執行後,doDispatcher方法中做了一個預設View的設定。

applyDefaultViewName(processedRequest, mv);private voidapplyDefaultViewName(HttpServletRequest request, ModelAndView mv) throws Exception {if (mv != null && !mv.hasView()) {

mv.setViewName(getDefaultViewName(request));

}

}

而這個getDefaultViewName是通過RequestToViewNameTranslator的實作類來解析的

protectedString getDefaultViewName(HttpServletRequest request) throws Exception {return this.viewNameTranslator.getViewName(request);

}

預設實作DefaultRequestToViewNameTranslator,根據配置的一些通用url進行比對

public發表于 2019-07-16 13:20

閱讀 ( 333 )

推薦

收藏