SpringMVC原理(5)-目标方法的执行

793 阅读5分钟

ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());:执行目标方法

执行完成会返回一个ModelAndView对象,如果是前后端不分离ModelAndView就会有值,如果是前后端分离返回json格式的数据的话ModelAndView就没有值。json是直接通过response写出去了

invokeHandlerMethod()

再上一篇拿到的HandlerAdapterRequestMappingHandlerAdapter,这个类中的invokeHandlerMethod()是执行目标方法的核心。我们直接来分析这个方法

 protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
                                            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
 ​
     // 1、把request和response封装起来
     ServletWebRequest webRequest = new ServletWebRequest(request, response);
     try {
         // ======这里都是一堆初始化工作=====
         // 获取一个数据绑定器的工厂
         WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
         // 获取一个Model的工厂
         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;
         }
 ​
         // 得到ModelAndView对象
         return getModelAndView(mavContainer, modelFactory, webRequest);
     }
     finally {
         webRequest.requestCompleted();
     }
 }

流程:

  1. 创建了一个ServletInvocableHandlerMethod目标方法的处理器),它扩展了InvocableHandlerMethod,它又扩展了HandlerMethod

    1. HandlerMethod就是我们之前拿到的目标方法,也就是处理器
    2. InvocableHandlerMethod使其支持能够通过HandlerMethodArgumentResolver来解析参数
    3. ServletInvocableHandlerMethod使其支持能够通过HandlerMethodReturnValueHandler来处理返回值、@ResponseStatus注解 等等功能
  2. 一堆初始化工作:数据绑定器工厂、Model工厂、参数解析器、返回值处理器

  3. 异步的工作

  4. 调用invokeAndHandle()执行目标方法

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

流程:

  1. invokeForRequest():执行目标方法拿到返回值
    1. 利用参数解析器来解析请求携带的参数的值
    2. 利用反射执行目标方法
  2. returnValueHandlers.handleReturnValue():遍历所有返回值处理器,使用返回值处理器处理返回值

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

参数解析器解析参数-getMethodArgumentValues()

使用参数解析器来解析请求携带的参数的值 HandlerMethodArgumentResolver

 // 参数解析器的组合,里面封装了所有参数解析器
 private HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite();
 ​
 protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
                                            Object... providedArgs) throws Exception {
 ​
     // 1、获取目标方法所有的参数
     MethodParameter[] parameters = getMethodParameters();
     if (ObjectUtils.isEmpty(parameters)) {
         return EMPTY_ARGS;
     }
 ​
     Object[] args = new Object[parameters.length];
     // 2、遍历目标方法所有的参数
     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;
         }
         // 3、使用参数解析器解析判断是否支持解析这种参数
         if (!this.resolvers.supportsParameter(parameter)) {
             throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
         }
         try {
             // 4、使用参数解析器来解析参数
             args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
         }
         catch (Exception ex) {
             // 5、如果有异常
             // Leave stack trace for later, exception may actually be resolved and handled...
             if (logger.isDebugEnabled()) {
                 String exMsg = ex.getMessage();
                 if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
                     logger.debug(formatArgumentError(parameter, exMsg));
                 }
             }
             throw ex;
         }
     }
     return args;
 }

其实核心就是利用各种参数解析器来解析参数的值,所以我们把参数解析器搞明白就知道了。

  1. 调用getMethodParameters()获取目标方法上的所有参数

  2. 遍历目标方法上所有的参数,并把传递过来的参数的值绑定到对应的参数上

    1. this.resolvers.supportsParameter():遍历所有参数解析器,调用其supportsParameter()来判断是否支持解析此参数,如果支持就放入缓存中,然后返回

      1. 其实就是判断对应的参数上有没有对应的注解修饰:@RequestParam@PathVariable、...
    2. this.resolvers.resolveArgument():从缓存中拿到上一步放入的参数解析器,然后调用其resolveArgument()来解析参数

2.1、this.resolvers.supportsParameter(parameter)

 // 参数解析器的缓存
 private final Map<MethodParameter, HandlerMethodArgumentResolver> argumentResolverCache =
     new ConcurrentHashMap<>(256);
 ​
 private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
     // 先从缓存中拿,缓存中没有再遍历
     HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
     if (result == null) {
         for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
             // 调用参数解析器的supportsParameter()判断是否支持处理这种类型的参数
             if (resolver.supportsParameter(parameter)) {
                 result = resolver;
                 // 放到缓存中
                 this.argumentResolverCache.put(parameter, result);
                 break;
             }
         }
     }
     return result;
 }

2.2、this.resolvers.resolveArgument()

 public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
                               NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
 ​
     // 还是上面的那个方法,上一步因为已经放过了,所以会从缓存中拿
     HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
     if (resolver == null) {
         throw new IllegalArgumentException("Unsupported parameter type [" +
                                            parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
     }
     // 解析参数并返回请求携带的参数值
     return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
 }

默认是有27个参数解析器

image.png

反射执行目标方法-doInvoke()

就是使用反射来执行目标方法

 protected Object doInvoke(Object... args) throws Exception {
     ReflectionUtils.makeAccessible(getBridgedMethod());
     try {
         // 利用反射给目标方法携带参数,然后执行目标方法
         return getBridgedMethod().invoke(getBean(), args);
     }
     
     // 省略代码
     ...
 }

返回值处理器处理返回值-handleReturnValue()

使用返回值处理器来处理返回值 HandlerMethodReturnValueHandler

 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);
 }
  1. 调用selectHandler()得到一个返回值处理器
  2. 调用返回值处理器的handleReturnValue()来处理返回值

15个返回值处理器

image.png

具体的参数解析原理和返回值处理原理放在单独的文章来说,逻辑太多。

返回值处理原理:SpringMVC原理(7)-返回值的处理

参数解析原理:SpringMVC原理(6)-参数解析原理

总结

执行目标方法流程:

  1. 利用参数解析器来解析请求参数的值
  2. 执行目标方法
  3. 利用返回值处理器来处理返回值

HandlerMethod

  1. HandlerMethod就是我们之前拿到的目标方法,也就是处理器
  2. InvocableHandlerMethod使其支持能够通过HandlerMethodArgumentResolver来解析参数
  3. ServletInvocableHandlerMethod使其支持能够通过HandlerMethodReturnValueHandler来处理返回值、@ResponseStatus注解 等等功能

image.png