java前端控制器如何处理请求_Spring MVC源码(二) ----- DispatcherServlet 请求处理流程 面试必问...

前端控制器

前端控制器,即所谓的Front Controller,体现的是设计模式中的前端控制器模式。前端控制器处理所有从用户过来的请求。所有用户的请求都要通过前端控制器。SpringMVC框架和其他请求驱动的表示层框架一样,也是围绕一个将请求分发到相应控制器的核心Servlet来设计的。DispatcherServlet和其他框架中的Servlet不一样的地方在于,它和Spring容器无缝整合在了一起,因此你可以在SpringMVC中使用Spring容器所有的特性。

DispatcherServlet这个前端控制器,在SpringMVC中的作用,以官方文档中的配图来说明:

41db2b4c5434644cd69e3927b3be84ea.png

整个流程可以被大致描述为:一个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方法执行的主要操作时序图

252cadb075627906e30028d5cf3d6a50.png

请求路由

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

}

90cdf9876a0fcc260453e57c79832c4c.png

需要说明的一点是方法执行完成的返回值通过返回值处理器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 )

推荐

收藏

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值