SpringMVC底层——请求参数处理流程描述

虚幻大学 xuhss 134℃ 0评论

? 优质资源分享 ?

学习路线指引(点击解锁) 知识定位 人群定位
? Python实战微信订餐小程序 ? 进阶级 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。
?Python量化交易实战? 入门级 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统

在DispatcherServlet.java的doDispatch方法中,springmvc通过handlermapping里面找哪个handler能处理请求,handler封装了目标方法的信息,

mappedHandler = getHandler(processedRequest);

然后为当前的handler找到一个适配器HandlerAdapter,寻找的过程为:在DispatcherServlet.java的getHandlerAdapter方法中,挨个匹配,判断当前adapter是否支持当前handler,判断方法为只要handler是handlerMethod类型就生效,就支持

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
if (this.handlerAdapters != null) {
    for (HandlerAdapter adapter : this.handlerAdapters) {
        if (adapter.supports(handler)) {
            return adapter;
            }
    }
}

找到适配器以后判断当前请求是不是“GET”方法以及“HEAD”,“HEAD”不是服务器真正处理的

适配器HandlerAdapter把(目标方法、request、response)传入handle执行目标方法

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

怎么执行目标方法:

  • 先得到handler
return this.handler;
  • 再进入内部处理细节RequestMappingHandlerAdapter.java,调用的invokeHandlerMethod就是执行目标方法
mav = invokeHandlerMethod(request,response,handlerMethod);
  • 在RequestMappingHandlerAdapter.java的invokeHandlerMethod方法中,

    • 为invocableMethod方法设置参数解析器argumentResolvers,参数解析器确定将要执行的目标方法的每一个参数的值是什么

      • 当前解析器是否支持解析这种参数
      • 支持就调用 resolveArgument
    • 为invocableMethod方法设置返回值处理器returnValueHandlers
  • 把26个argumentResolvers和15个returnValueHandlers都放入目标方法包装的ServletInvocableHandlerMethod中
  • 然后真正执行目标方法的语句
invocableMethod.invokeAndHandle(WebRequest,mavContainer);
+ 在ServletInvocableHandlerMethod.java的invokeAndHandle方法中,执行了controller

```
Object returnValue = invokeForRequest(webRequest,mavContainer,proviedArgs);

```

    - step into 进入InvocableHandlerMethod.java,**确定目标方法每一个参数的值**

    ```
    Object[] agrs = getMethodArgumentValues(request,mavContainer,providerArgs)

    ```

        * 在InvocableHandlerMethod.java的getMethodArgumentValues方法中,先获取方法所有的参数声明(详细信息)。

        ```
        MethodParameter[] parameters = getMethodParameters();

        ```
        * 判断参数是否为空,为空则无需确定任何值直接返回;

        ```
        if (ObjectUtils.isEmpty(parameters)) {
            return EMPTY_ARGS;
        }

        ```

        如果有参数列表,new一个Object[],参数列表有多少个Object[]就有多长

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

        ```

        先声明args遍历parameters,给args[i]赋值,args[i]的值解析器解析了才有
        * 解析之前,判断26个解析器是不是**supportsParamter支持**这个参数类型。

        ```
        this.resolvers.supportsParameter(parameter)

        ```

            + HandlerMethodArgumentResolverComposite.java的getArgumentResolver方法中
            + 获取一个缓存result
            + result==null,进入增强for循环,逐个确定26个解析器谁能支持这种参数

                - supportsParameter方法,传来的参数有没有hasParameterAnnotation标注注解
                - 没有就return false
                - 如果标了,再判断参数是否map类型,
                - return true支持解析
            + 当前resolver支持解析,放到缓存里边,判断成功,进入解析
        * **解析参数**

        ```
        this.resolvers.resolveArgument

        ```

            + HandlerMethodArgumentResolverComposite.java的resolverArgument方法中,先拿到所有的参数解析器getArgumentResolver
            + 调用参数解析器的resolverArgument方法进行解析
                - 获取参数名字信息
                - 解析参数的名字,placeholderResolved、BeanExpressionResolver解析evaluate计算名字,按照正则匹配的方式
                - 解析参数的值
                    * uriTemlateVars 在request请求域中拿到值;UrlPathHelper会把uri地址里边的所有的路径变量全部解析出来并保存到请求域中
        * 遍历循环所有参数
    - 最终返回args,args就是确定好的值
+ 处理返回结果的时候,把mavContainer传进去,

```
this.returnValueHandlers.handlerReturnValue

```

    - 在handlerMethod.java的getReturnValueType方法中获取返回的结果类型
    - HandlerMethodArgumentResolverComposite.java的handleReturnValue方法中,

    找到返回值的处理器

    如果返回值是一个字符串,拿到字符串然后保存到mavContainer
+ 返回值处理完以后,getModelAndView
  • 目标方法执行完成

将所有的数据都放在 ModelAndViewContainer;包含要去的页面地址View。还包含Model数据。

  • 从ModelAndViewContainer拿到默认的Model,updateBindingResult,拿到key放到绑定里边,又被封装成ModelAndView,然后返回这个新封装的mav

    • 处理派发结果
    processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    

    拿到所有请求域中的属性,解析得到视图名

    渲染页面

    view.render(mv.getModelInternal(),request,response);
    

    拿到页面数据

    createMergeOutputModel(model,request,response);
    创造合并的输出模型
    

    如果model不等于空

    mergeModel.putAll(model)//即把数据转移到HashMap
    

    渲染合并输出的模型数据

    renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
    
    - 把上面的Hashmap传进来了
    - 拿到请求对象,获取的原生的Servletrequest
    
    ```
    return originalRequest
    
    ```
    - 暴露模型作为请求域属性
    
    ```
    // Expose the model object as request attributes.
            exposeModelAsRequestAttributes(model, request);
    
    ```
    
        * 把model里面的东西进行遍历
        * 遍历以后每一个request setAttribute

转载请注明:xuhss » SpringMVC底层——请求参数处理流程描述

喜欢 (0)

您必须 登录 才能发表评论!