第10章-SpringMVC中的HandlerAdapter源码解析 测试类 HelloController package  cn.imlql.web.controller;@Controller public  class  HelloController   {	public  HelloController ()   { 		System.out.println("HelloController....." ); 	} 	@Autowired  	HelloService helloService; 	@GetMapping("/hello")  	public  String sayHello (String name,  						   @RequestParam("user")  String user, 						   HttpSession session)   {		String mvc = helloService.say(user + ":MVC"  + name); 		session.setAttribute("msg" , mvc); 		return  "index.jsp" ; 	} } 
 
index.jsp <%@ page contentType="text/html;charset=UTF-8"  language="java"  %> <html>   <head>     <title>$Title$</title>   </head>   <body>   $END$   结果: <h1 style="color: red">${sessionScope.msg}</h1>   </body> </html> 
 
其余的类和前面一样,不列举了。
BeanNameUrlHandlerMapping简介 public  class  BeanNameUrlHandlerMapping  extends  AbstractDetectingUrlHandlerMapping   {       @Override       protected  String[] determineUrlsForHandler(String beanName) {       List<String> urls = new  ArrayList<>();       if  (beanName.startsWith("/" )) {          urls.add(beanName);       }       String[] aliases = obtainApplicationContext().getAliases(beanName);       for  (String alias : aliases) {          if  (alias.startsWith("/" )) {             urls.add(alias);          }       }       return  StringUtils.toStringArray(urls);    } } 
 
很简单,意思就是只要你的BeanName是以/开头,就会将这个Bean封装成一个BeanNameUrlHandlerMapping映射。 
具体路径怎么写呢?你可以在你的类上写一个@Controller("/helloReq") ,这样就有路径了。代表的意思就是/helloReq这个URL和由哪个handler来处理的映射关系被保存在了BeanNameUrlHandlerMapping里 
如果不懂的话可以待会看下面的例子 
 
handler就是咱们常说的XXXController
 
HandlerAdapter概述 
上面我们从HandlerMapping这个映射中心找到了由哪个Controller执行哪个方法 
按照我们最简单的想法就是直接method.invoke()反射执行 
但是实际上我们要考虑
是哪个对象执行方法? 
方法里的参数有几个? 
参数类型是什么?参数类型大概率有我们自己写的类,怎么处理 
多个参数我们还要一个一个赋值。 
怎么返回?是直接返回值,还是跳转页面,等等 
 
 
其实是比较复杂的,springmvc就写了一个HandlerAdapter来处理这些复杂的逻辑 
 
还是跟HandlerMapping一样,继续Debug DispatcherServlet#doDispatch(HttpServletRequest, HttpServletResponse)
浏览器输入:http://localhost:8080/springmvc_source_test/hello?name=zhangsan&user=haha开始测试 
DispatcherServlet#doDispatch()请求派发  
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);                    mappedHandler = getHandler(processedRequest);          if  (mappedHandler == null ) {               noHandlerFound(processedRequest, response);             return ;          }                    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());                    String method = request.getMethod();          boolean  isGet = "GET" .equals(method);          if  (isGet || "HEAD" .equals(method)) {             long  lastModified = ha.getLastModified(request, mappedHandler.getHandler());             if  (new  ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {                return ;             }          }                    if  (!mappedHandler.applyPreHandle(processedRequest, response)) {             return ;           }                    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) {                              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()) {                    if  (mappedHandler != null ) {             mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);          }       }       else  {                    if  (multipartRequestParsed) {             cleanupMultipart(processedRequest);          }       }    } } 
 
F7进入getHandlerAdapter(mappedHandler.getHandler())
DispatcherServlet#getHandlerAdapter()  
上面几个默认的适配器还是在DispatcherServlet.properties配置的4个默认适配器,然后在初始化九大组件的时候放到容器里
HttpRequestHandlerAdapter#supports() @Override  public  boolean  supports (Object handler)   {    return  (handler instanceof  HttpRequestHandler); } 
 
这里判断当前handler【就是咱们写的Controller】是否实现了HttpRequestHandler接口,是的话就直接返回这个Adapter,不往下走了
SimpleControllerHandlerAdapter#supports() @Override public  boolean  supports (Object handler)   {   return  (handler instanceof  Controller); } 
 
同理,这里判断当前handler是否实现了Controller接口,是的话就直接返回这个Adapter,不往下走了
RequestMappingHandlerAdapter RequestMappingHandlerAdapter自己没有写supports方法,它用的是父类的AbstractHandlerMethodAdapter的
AbstractHandlerMethodAdapter#supports() public  final  boolean  supports (Object handler)   {   return  (handler instanceof  HandlerMethod && supportsInternal((HandlerMethod) handler)); } 
 
这个就是判断当前handler是不是HandlerMethod类型的,前面大致讲过只要标注了@RequestMapping注解的handler最终都会被封装成HandlerMethod
 
RequestMappingHandlerAdapter#supportsInternal() protected  boolean  supportsInternal (HandlerMethod handlerMethod)   {   return  true ; } 
 
DispatcherServlet#doDispatch()  
举例说明HttpRequestHandlerAdapter和SimpleControllerHandlerAdapter如何与BeanNameUrlHandlerMapping联动 测试类-HelloHttpRequestHandler @Controller("/helloReq")  public  class  HelloHttpRequestHandler  implements  HttpRequestHandler   {           @Override     public  void  handleRequest (HttpServletRequest request,                         HttpServletResponse response)  throws  ServletException, IOException  {      response.getWriter().write("HelloHttpRequestHandler...." );    } } 
 
@Controller("/helloReq")里的/helloReq即是BeanName也是URL。这里就是之前说的BeanName以/为开头的Bean,它的URL和handler的映射关系会被保存在BeanNameUrlHandlerMapping里,如下图
 
DispatcherServlet#getHandlerAdapter()  
因为我们的HelloHttpRequestHandler正好实现了HttpRequestHandler,所以就会直接返回HttpRequestHandlerAdapter
DispatcherServlet#doDispatch() 我们直接来到准备执行的地方
 
F7进入ha.handle(processedRequest, response, mappedHandler.getHandler())
HttpRequestHandlerAdapter#handle()  
直接来到了这里,接着就调用我们自定义的HelloHttpRequestHandler的handleRequest方法。
测试类-HelloSimpleController @Controller("/helloSimple") public  class  HelloSimpleController  implements  Controller   {   @Override     public  ModelAndView handleRequest (HttpServletRequest request, HttpServletResponse response)  throws  Exception  {       return  null ;    } } 
 
实现Controller接口的就是SimpleControllerHandlerAdapter来处理,原理和HttpRequestHandlerAdapter几乎一样。
小总结 
很显然BeanNameUrlHandlerMapping和HttpRequestHandlerAdapter的结合,一个类只能处理一个URL路径的请求。并且这里的参数处理都很麻烦,不像@RequestMapping那么方便 
远不如RequestMappingHandlerMapping和RequestMappingHandlerAdapter的结合来的方便。它两结合后,一个类里可以写多个@RequestMapping注解标注的方法,一个类里就可以处理多个URL请求,并且处理参数和返回值都很方便。 
所以下面就重点讲RequestMappingHandlerAdapter 
 
RequestMappingHandlerAdapter中的参数解析器、返回值处理器=>概述 DispatcherServlet#doDispatch()  
AbstractHandlerMethodAdapter#handle() public  final  ModelAndView handle (HttpServletRequest request, HttpServletResponse response, Object handler)       throws  Exception  {   return  handleInternal(request, response, (HandlerMethod) handler); } 
 
AbstractHandlerMethodAdapter是RequestMappingHandlerAdapter的父类,之前说过
RequestMappingHandlerAdapter#handleInternal()    protected  ModelAndView handleInternal (HttpServletRequest request,           HttpServletResponse response, HandlerMethod handlerMethod)  throws  Exception  {      ModelAndView mav;       checkRequest(request);              if  (this .synchronizeOnSession) {          HttpSession session = request.getSession(false );          if  (session != null ) {             Object mutex = WebUtils.getSessionMutex(session);             synchronized  (mutex) {                 mav = invokeHandlerMethod(request, response, handlerMethod);             }          }          else  {                          mav = invokeHandlerMethod(request, response, handlerMethod);          }       }       else  {                    mav = invokeHandlerMethod(request, response, handlerMethod);       }       if  (!response.containsHeader(HEADER_CACHE_CONTROL)) {          if  (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {             applyCacheSeconds(response, this .cacheSecondsForSessionAttributeHandlers);          }          else  {             prepareResponse(response);          }       }       return  mav;    }     private  boolean  synchronizeOnSession = false ;
 
 
RequestMappingHandlerAdapter#invokeHandlerMethod( ) @Nullable protected  ModelAndView invokeHandlerMethod (HttpServletRequest request,       HttpServletResponse response, HandlerMethod handlerMethod)  throws  Exception  {       ServletWebRequest webRequest = new  ServletWebRequest(request, response);    try  {        WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);               ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);                    ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);       if  (this .argumentResolvers != null ) {           invocableMethod.setHandlerMethodArgumentResolvers(this .argumentResolvers);       }       if  (this .returnValueHandlers != null ) {           invocableMethod.setHandlerMethodReturnValueHandlers(this .returnValueHandlers);       }       invocableMethod.setDataBinderFactory(binderFactory);       invocableMethod.setParameterNameDiscoverer(this .parameterNameDiscoverer);                     ModelAndViewContainer mavContainer = new  ModelAndViewContainer();       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();          LogFormatUtils.traceDebug(logger, traceOn -> {             String formatted = LogFormatUtils.formatValue(result, !traceOn);             return  "Resume with async result ["  + formatted + "]" ;          });          invocableMethod = invocableMethod.wrapConcurrentResult(result);       }              invocableMethod.invokeAndHandle(webRequest, mavContainer);       if  (asyncManager.isConcurrentHandlingStarted()) {          return  null ;       }       return  getModelAndView(mavContainer, modelFactory, webRequest);    }    finally  {       webRequest.requestCompleted();    } } 
 
什么是WebDataBinderFactory? public  String sayHello (Person person)  { } 
 
假设方法里有一个Person类型的参数,Person里的属性就是age,name,sex这些的 
前端传的参数名刚好能和Person的属性对上,WebDataBinder就会帮我们自动绑定上。 
 
argumentResolvers参数解析器  
注意有一些解析器,比如RequestResponseBodyMethodProcessor即是返回值解析器也是参数解析器
returnValueHandlers返回值解析器  
15个参数解析器和27个返回值解析器是什么时候有值的? public  class  RequestMappingHandlerAdapter  extends  AbstractHandlerMethodAdapter       implements  BeanFactoryAware , InitializingBean   {     } 
 
我们可以看到RequestMappingHandlerAdapter也是实现了InitializingBean接口,所以它什么时候有值,和RequestMappingHandlerMapping是一样的逻辑
DispatcherServlet#onRefresh()开始初始化九大组件,就会开始初始化HandlerAdapter 
首先是创建DispatcherServlet.properties里指定的四个HandlerAdapter实现类的对象。还是用createBean来创建HandlerAdapter的 
其中RequestMappingHandlerAdapter创建完对象后,因为它实现了InitializingBean,所以会调用RequestMappingHandlerAdapter#afterPropertiesSet() 
在afterPropertiesSet()中就直接new了所有默认的参数解析器和返回值解析器 
 
RequestMappingHandlerAdapter#afterPropertiesSet() public  void  afterPropertiesSet ()   {        initControllerAdviceCache();      if  (this .argumentResolvers == null ) {         List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();       this .argumentResolvers = new  HandlerMethodArgumentResolverComposite().addResolvers(resolvers);     }    if  (this .initBinderArgumentResolvers == null ) {       List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();       this .initBinderArgumentResolvers = new  HandlerMethodArgumentResolverComposite().addResolvers(resolvers);    }    if  (this .returnValueHandlers == null ) {       List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();       this .returnValueHandlers = new  HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);    } } 
 
RequestMappingHandlerAdapter#getDefaultArgumentResolvers() private  List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers ()   {   List<HandlerMethodArgumentResolver> resolvers = new  ArrayList<>(30 );            resolvers.add(new  RequestParamMethodArgumentResolver(getBeanFactory(), false ));    resolvers.add(new  RequestParamMapMethodArgumentResolver());    resolvers.add(new  PathVariableMethodArgumentResolver());    resolvers.add(new  PathVariableMapMethodArgumentResolver());    resolvers.add(new  MatrixVariableMethodArgumentResolver());    resolvers.add(new  MatrixVariableMapMethodArgumentResolver());    resolvers.add(new  ServletModelAttributeMethodProcessor(false ));    resolvers.add(new  RequestResponseBodyMethodProcessor(getMessageConverters(), this .requestResponseBodyAdvice));    resolvers.add(new  RequestPartMethodArgumentResolver(getMessageConverters(), this .requestResponseBodyAdvice));    resolvers.add(new  RequestHeaderMethodArgumentResolver(getBeanFactory()));    resolvers.add(new  RequestHeaderMapMethodArgumentResolver());    resolvers.add(new  ServletCookieValueMethodArgumentResolver(getBeanFactory()));    resolvers.add(new  ExpressionValueMethodArgumentResolver(getBeanFactory()));    resolvers.add(new  SessionAttributeMethodArgumentResolver());    resolvers.add(new  RequestAttributeMethodArgumentResolver());        resolvers.add(new  ServletRequestMethodArgumentResolver());    resolvers.add(new  ServletResponseMethodArgumentResolver());    resolvers.add(new  HttpEntityMethodProcessor(getMessageConverters(), this .requestResponseBodyAdvice));    resolvers.add(new  RedirectAttributesMethodArgumentResolver());    resolvers.add(new  ModelMethodProcessor());    resolvers.add(new  MapMethodProcessor());    resolvers.add(new  ErrorsMethodArgumentResolver());    resolvers.add(new  SessionStatusMethodArgumentResolver());    resolvers.add(new  UriComponentsBuilderMethodArgumentResolver());    if  (KotlinDetector.isKotlinPresent()) {       resolvers.add(new  ContinuationHandlerMethodArgumentResolver());    }        if  (getCustomArgumentResolvers() != null ) {       resolvers.addAll(getCustomArgumentResolvers());    }        resolvers.add(new  PrincipalMethodArgumentResolver());        resolvers.add(new  RequestParamMethodArgumentResolver(getBeanFactory(), true ));    resolvers.add(new  ServletModelAttributeMethodProcessor(true ));    return  resolvers; } 
 
RequestMappingHandlerAdapter#getDefaultReturnValueHandlers() private  List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers ()   {   List<HandlerMethodReturnValueHandler> handlers = new  ArrayList<>(20 );        handlers.add(new  ModelAndViewMethodReturnValueHandler());    handlers.add(new  ModelMethodProcessor());    handlers.add(new  ViewMethodReturnValueHandler());    handlers.add(new  ResponseBodyEmitterReturnValueHandler(getMessageConverters(),          this .reactiveAdapterRegistry, this .taskExecutor, this .contentNegotiationManager));    handlers.add(new  StreamingResponseBodyReturnValueHandler());    handlers.add(new  HttpEntityMethodProcessor(getMessageConverters(),          this .contentNegotiationManager, this .requestResponseBodyAdvice));    handlers.add(new  HttpHeadersReturnValueHandler());    handlers.add(new  CallableMethodReturnValueHandler());    handlers.add(new  DeferredResultMethodReturnValueHandler());    handlers.add(new  AsyncTaskMethodReturnValueHandler(this .beanFactory));        handlers.add(new  ServletModelAttributeMethodProcessor(false ));    handlers.add(new  RequestResponseBodyMethodProcessor(getMessageConverters(),          this .contentNegotiationManager, this .requestResponseBodyAdvice));        handlers.add(new  ViewNameMethodReturnValueHandler());    handlers.add(new  MapMethodProcessor());        if  (getCustomReturnValueHandlers() != null ) {       handlers.addAll(getCustomReturnValueHandlers());    }        if  (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {       handlers.add(new  ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));    }    else  {       handlers.add(new  ServletModelAttributeMethodProcessor(true ));    }    return  handlers; } 
 
RequestMappingHandlerAdapter中的参数解析器工作流程 DispatcherServlet#doDispatch()  
AbstractHandlerMethodAdapter#handle(HttpServletRequest , HttpServletResponse , Object )和RequestMappingHandlerAdapter#handleInternal(HttpServletRequest , HttpServletResponse , HandlerMethod )上面说过,跳过
RequestMappingHandlerAdapter#invokeHandlerMethod()准备执行目标方法  
ServletInvocableHandlerMethod#invokeAndHandle()真正开始执行目标方法 public  void  invokeAndHandle (ServletWebRequest webRequest, ModelAndViewContainer mavContainer,       Object... providedArgs)  throws  Exception  {       Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);    setResponseStatus(webRequest);    if  (returnValue == null ) {       if  (isRequestNotModified(webRequest) || getResponseStatus() != null  || mavContainer.isRequestHandled()) {          disableContentCachingIfNecessary(webRequest);          mavContainer.setRequestHandled(true );          return ;       }    }    else  if  (StringUtils.hasText(getResponseStatusReason())) {       mavContainer.setRequestHandled(true );       return ;    }    mavContainer.setRequestHandled(false );    Assert.state(this .returnValueHandlers != null , "No return value handlers" );    try  {       this .returnValueHandlers.handleReturnValue(             returnValue, getReturnValueType(returnValue), mavContainer, webRequest);    }    catch  (Exception ex) {       if  (logger.isTraceEnabled()) {          logger.trace(formatErrorForReturnValue(returnValue), ex);       }       throw  ex;    } } 
 
InvocableHandlerMethod#invokeForRequest( )目标方法的反射执行过程 public  Object invokeForRequest (NativeWebRequest request, @Nullable  ModelAndViewContainer mavContainer,       Object... providedArgs)  throws  Exception  {       Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);    if  (logger.isTraceEnabled()) {       logger.trace("Arguments: "  + Arrays.toString(args));    }    return  doInvoke(args);  } 
 
 
开始进入正题
InvocableHandlerMethod#getMethodArgumentValues()获取方法的请求参数 protected  Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable  ModelAndViewContainer mavContainer,      Object... providedArgs) throws  Exception {            MethodParameter[] parameters = getMethodParameters();    if  (ObjectUtils.isEmpty(parameters)) {       return  EMPTY_ARGS;    }        Object[] args = new  Object[parameters.length];    for  (int  i = 0 ; i < parameters.length; i++) {       MethodParameter parameter = parameters[i];       parameter.initParameterNameDiscovery(this .parameterNameDiscoverer);       args[i] = findProvidedArgument(parameter, providedArgs);        if  (args[i] != null ) {          continue ;       }       if  (!this .resolvers.supportsParameter(parameter)) {           throw  new  IllegalStateException(formatArgumentError(parameter, "No suitable resolver" ));       }       try  {          args[i] = this .resolvers.resolveArgument(parameter, mavContainer, request, this .dataBinderFactory);       }       catch  (Exception ex) {                    if  (logger.isDebugEnabled()) {             String exMsg = ex.getMessage();             if  (exMsg != null  && !exMsg.contains(parameter.getExecutable().toGenericString())) {                logger.debug(formatArgumentError(parameter, exMsg));             }          }          throw  ex;       }    }    return  args; } 
 
 
HandlerMethodArgumentResolverComposite准备循环27个参数解析器  
HandlerMethodArgumentResolverComposite#supportsParameter() public  boolean  supportsParameter (MethodParameter parameter)   {   return  getArgumentResolver(parameter) != null ; } 
 
HandlerMethodArgumentResolverComposite#getArgumentResolver()循环判断哪个参数解析器支持这个参数 private  HandlerMethodArgumentResolver getArgumentResolver (MethodParameter parameter)   {   HandlerMethodArgumentResolver result = this .argumentResolverCache.get(parameter);     if  (result == null ) {       for  (HandlerMethodArgumentResolver resolver : this .argumentResolvers) {          if  (resolver.supportsParameter(parameter)) {             result = resolver;             this .argumentResolverCache.put(parameter, result);             break ;          }       }    }    return  result; } 
 
这里就是循环27个参数解析器,看哪一个能解析这种类型的参数。因为参数解析器太多,我们就举几个常用的例子
RequestParamMethodArgumentResolver判断@RequestParam注解的参数解析器 package  org.springframework.web.method.annotation    public  boolean  supportsParameter (MethodParameter parameter)   {        if  (parameter.hasParameterAnnotation(RequestParam.class)) {                      if  (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {              RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class);              return  (requestParam != null  && StringUtils.hasText(requestParam.name()));           }           else  {              return  true ;           }        }        else  {           if  (parameter.hasParameterAnnotation(RequestPart.class)) {              return  false ;           }           parameter = parameter.nestedIfOptional();           if  (MultipartResolutionDelegate.isMultipartArgument(parameter)) {              return  true ;           }           else  if  (this .useDefaultResolution) {              return  BeanUtils.isSimpleProperty(parameter.getNestedParameterType());           }           else  {              return  false ;           }        }     } 
 
这个就是判断参数有没有标@RequestParam注解
注意这个是org.springframework.web.method.annotation包下的
 
 
第一次进入RequestParamMethodArgumentResolver#supportsParameter(MethodParameter parameter)时,我们在前面讲过,在RequestMappingHandlerAdapter#getDefaultArgumentResolvers()添加默认解析器的时候,spring往参数解析器里加了两个 
 
    resolvers.add(new  RequestParamMethodArgumentResolver(getBeanFactory(), false ));                resolvers.add(new  RequestParamMethodArgumentResolver(getBeanFactory(), true )); 
 
这里的true和false指定的就是useDefaultResolution这个东西
 
然后我们验证一下第二个RequestParamMethodArgumentResolver
 
 
 
useDefaultResolution这个看名字应该就是前面25个处理器都用不到的时候,就用这个默认中的默认处理器第26个RequestParamMethodArgumentResolver(双重默认) 
那什么时候用第27个ServletModelAttributeMethodProcessor这个处理器呢?当第26个在上面那几个if else中返回false,就会用最后这个,至于什么时候返回false,我没有深入研究。 
 
RequestParamMapMethodArgumentResolver参数解析器 
@RequestParam Map<String,Object> params
 
public  boolean  supportsParameter (MethodParameter parameter)   {   RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class);    return  (requestParam != null  && Map.class.isAssignableFrom(parameter.getParameterType()) &&          !StringUtils.hasText(requestParam.name())); } 
 
判断有没有标@RequestParam注解,并且类型是Map
PathVariableMethodArgumentResolver判断@PathVariable注解的参数解析器 public  boolean  supportsParameter (MethodParameter parameter)   {   if  (!parameter.hasParameterAnnotation(PathVariable.class)) {       return  false ;    }    if  (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {       PathVariable pathVariable = parameter.getParameterAnnotation(PathVariable.class);       return  (pathVariable != null  && StringUtils.hasText(pathVariable.value()));    }    return  true ; } 
 
相信大家已经能猜到了,这里就是判断参数上有没有标注@PathVariable注解
返回到InvocableHandlerMethod#getMethodArgumentValues( )  
具体的参数赋值过程,就是一些数据类型的转换,可以自己去看下。
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory); 
 
返回到InvocableHandlerMethod#invokeForRequest()  
接下来就是交给反射去执行
返回到ServletInvocableHandlerMethod#invokeAndHandle()  
拿到返回值了,接下来交给返回值处理器
SpringMVC到底能写哪些参数? 详见官方文档-参数相关 
RequestMappingHandlerAdapter中的返回值解析器工作流程 @Controller public  class  HelloController   {	public  HelloController ()   { 		System.out.println("HelloController....." ); 	} 	@Autowired  	HelloService helloService; 	@GetMapping("/hello")   	public  String sayHello (String name,   						   @RequestParam("user")  String user, 						   HttpSession session, HttpServletRequest request, //原生的session对象 						   @RequestHeader("User-Agent")  String ua)   { 		 		String header = request.getHeader("User-Agent" ); 		 		 		 		String mvc = helloService.say(user + ":MVC"  + name); 		session.setAttribute("msg" , mvc); 		 		 		return  "index.jsp" ; 	} } 
 
ServletInvocableHandlerMethod#invokeAndHandle()  
我们可以看到RequestResponseBodyMethodProcessor比ViewNameMethodReturnValueHandler优先级高,接下来我们细讲
HandlerMethodReturnValueHandlerComposite#handleReturnValue() @Override public  void  handleReturnValue (@Nullable  Object returnValue, MethodParameter returnType,       ModelAndViewContainer mavContainer, NativeWebRequest webRequest)  throws  Exception  {       HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);    if  (handler == null ) {       throw  new  IllegalArgumentException("Unknown return value type: "  + returnType.getParameterType().getName());    }     handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest); } 
 
HandlerMethodReturnValueHandlerComposite#selectHandler()循环15个返回值处理器找到合适的返回值处理器 private  HandlerMethodReturnValueHandler selectHandler (@Nullable  Object value, MethodParameter returnType)   {   boolean  isAsyncValue = isAsyncReturnValue(value, returnType);        for  (HandlerMethodReturnValueHandler handler : this .returnValueHandlers) {       if  (isAsyncValue && !(handler instanceof  AsyncHandlerMethodReturnValueHandler)) {          continue ;       }       if  (handler.supportsReturnType(returnType)) {          return  handler;       }    }    return  null ; } 
 
我们就直接放行,看最终找到的是哪个
 
ViewNameMethodReturnValueHandler#supportsReturnType() public  boolean  supportsReturnType (MethodParameter returnType)   {   Class<?> paramType = returnType.getParameterType();        return  (void .class == paramType || CharSequence.class.isAssignableFrom(paramType)); } 
 
返回到HandlerMethodReturnValueHandlerComposite#handleReturnValue()  
ViewNameMethodReturnValueHandler#handleReturnValue()开始处理返回值 public  void  handleReturnValue (@Nullable  Object returnValue, MethodParameter returnType,       ModelAndViewContainer mavContainer, NativeWebRequest webRequest)  throws  Exception  {   if  (returnValue instanceof  CharSequence) {        String viewName = returnValue.toString();       mavContainer.setViewName(viewName);       if  (isRedirectViewName(viewName)) {           mavContainer.setRedirectModelScenario(true );       }    }    else  if  (returnValue != null ) {              throw  new  UnsupportedOperationException("Unexpected return type: "  +             returnType.getParameterType().getName() + " in method: "  + returnType.getMethod());    } } 
 
 
然后就准备返回了
返回到RequestMappingHandlerAdapter#invokeHandlerMethod()  
RequestMappingHandlerAdapter#getModelAndView()进行视图解析相关工作 private  ModelAndView getModelAndView (ModelAndViewContainer mavContainer,       ModelFactory modelFactory, NativeWebRequest webRequest)  throws  Exception  {       modelFactory.updateModel(webRequest, mavContainer);    if  (mavContainer.isRequestHandled()) {       return  null ;    }    ModelMap model = mavContainer.getModel();    ModelAndView mav = new  ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());    if  (!mavContainer.isViewReference()) {       mav.setView((View) mavContainer.getView());    }    if  (model instanceof  RedirectAttributes) {       Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();       HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);       if  (request != null ) {           RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);       }    }    return  mav; } 
 
 
注意如果你返回值写index而不是index.jsp,它会给你报404。意思就是它不会给我们加jsp后缀。
返回到DispatcherServlet#doDispatch()  
DispatcherServlet#applyDefaultViewName()    private  void  applyDefaultViewName (HttpServletRequest request, @Nullable  ModelAndView mv)  throws  Exception  {       if  (mv != null  && !mv.hasView()) {           String defaultViewName = getDefaultViewName(request);           if  (defaultViewName != null ) {             mv.setViewName(defaultViewName);          }       }    } protected  String getDefaultViewName (HttpServletRequest request)  throws  Exception  {	return  (this .viewNameTranslator != null  ? this .viewNameTranslator.getViewName(request) : null ); } @Nullable  private  RequestToViewNameTranslator viewNameTranslator;
 
这里不是重点,我直接告诉你结果吧,默认页面就是把request的请求路径直接拿来当要去的页面地址 。
比如你的请求路径是@GetMapping("/hello.html"),但是你返回值写的是void,那么它就会给你返回到hello.html页面
返回到DispatcherServlet#doDispatch()  
来到拦截器的后置处理环节
 
然后来到处理结果环节
springmvc能写哪些返回值 官方文档:https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-return-types 
视图解析器解析流程 DispatcherServlet#processDispatchResult()处理返回值 private  void  processDispatchResult (HttpServletRequest request, HttpServletResponse response,       @Nullable  HandlerExecutionChain mappedHandler, @Nullable  ModelAndView mv,       @Nullable  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 );       }    }        if  (mv != null  && !mv.wasCleared()) {       render(mv, request, response);        if  (errorView) {          WebUtils.clearErrorRequestAttributes(request);       }    }    else  {       if  (logger.isTraceEnabled()) {          logger.trace("No view rendering, null ModelAndView returned." );       }    }    if  (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {              return ;    }    if  (mappedHandler != null ) {              mappedHandler.triggerAfterCompletion(request, response, null );    } } 
 
进入此方法
 
DispatcherServlet#render()渲染ModelAndView protected  void  render (ModelAndView mv, HttpServletRequest request, HttpServletResponse response)  throws  Exception  {       Locale locale =          (this .localeResolver != null  ? this .localeResolver.resolveLocale(request) : request.getLocale());    response.setLocale(locale);    View view;    String viewName = mv.getViewName();    if  (viewName != null ) {              view = resolveViewName(viewName, mv.getModelInternal(), locale, request);       if  (view == null ) {          throw  new  ServletException("Could not resolve view with name '"  + mv.getViewName() +                "' in servlet with name '"  + getServletName() + "'" );       }    }    else  {              view = mv.getView();       if  (view == null ) {          throw  new  ServletException("ModelAndView ["  + mv + "] neither contains a view name nor a "  +                "View object in servlet with name '"  + getServletName() + "'" );       }    }        if  (logger.isTraceEnabled()) {       logger.trace("Rendering view ["  + view + "] " );    }    try  {       if  (mv.getStatus() != null ) {          response.setStatus(mv.getStatus().value());       }       view.render(mv.getModelInternal(), request, response);    }    catch  (Exception ex) {       if  (logger.isDebugEnabled()) {          logger.debug("Error rendering view ["  + view + "]" , ex);       }       throw  ex;    } } 
 
DispatcherServlet#resolveViewName() protected  View resolveViewName (String viewName, @Nullable  Map<String, Object> model,       Locale locale, HttpServletRequest request)  throws  Exception  {   if  (this .viewResolvers != null ) {              for  (ViewResolver viewResolver : this .viewResolvers) {          View view = viewResolver.resolveViewName(viewName, locale);          if  (view != null ) {             return  view;          }       }    }    return  null ; } 
 
不过默认的视图解析器只有一个
 
这里没有拼接前缀和后缀,所以我们必须要自己写.jsp或者.html
RequestResponseBodyMethodProcessor即是返回值解析器也是参数解析器    @Override     public  boolean  supportsParameter (MethodParameter parameter)   {       return  parameter.hasParameterAnnotation(RequestBody.class);    }    @Override     public  boolean  supportsReturnType (MethodParameter returnType)   {       return  (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||             returnType.hasMethodAnnotation(ResponseBody.class));    } public  Object resolveArgument (MethodParameter parameter, @Nullable  ModelAndViewContainer mavContainer, 		NativeWebRequest webRequest, @Nullable  WebDataBinderFactory binderFactory)  throws  Exception  {	parameter = parameter.nestedIfOptional(); 	Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType()); 	String name = Conventions.getVariableNameForParameter(parameter); 	if  (binderFactory != null ) { 		WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name); 		if  (arg != null ) { 			validateIfApplicable(binder, parameter); 			if  (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) { 				throw  new  MethodArgumentNotValidException(parameter, binder.getBindingResult()); 			} 		} 		if  (mavContainer != null ) { 			mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult()); 		} 	} 	return  adaptArgumentIfNecessary(arg, parameter); } @Override   public  void  handleReturnValue (@Nullable  Object returnValue, MethodParameter returnType, 		ModelAndViewContainer mavContainer, NativeWebRequest webRequest) 		throws  IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException  {	mavContainer.setRequestHandled(true ); 	ServletServerHttpRequest inputMessage = createInputMessage(webRequest); 	ServletServerHttpResponse outputMessage = createOutputMessage(webRequest); 	 	writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage); } 
 
由于现在的前后端分离时代,我们直接返回视图的需求已经很少很少了。现在一般都是直接返回数据,所以视图解析器详细原理不再细述,后面就直接开始讲异常处理流程。