Spring-MVC 源码分析--DispatcherServlet 请求分发&访问&返回

发布时间:2023年12月20日


前言

Spring-MVC 对DispatcherServlet 完成初始化之后,下面看下一个http 请求是如何被分发到不同请求处理handlerMapping 。


一、handlerMapping 的匹配 :

在spring-mvc 中对于每种情形的http 访问,对由一个handlerMapping 进行处理,接下来先看下spring-mvc对于handlerMapping 是如何选择的?

1.1 HttpServlet 请求匹配:

请求进来: HttpServlet -->service 方法

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String method = req.getMethod();
    long lastModified;
    if (method.equals("GET")) {
        lastModified = this.getLastModified(req);
        if (lastModified == -1L) {
            this.doGet(req, resp);
        } else {
            long ifModifiedSince;
            try {
                ifModifiedSince = req.getDateHeader("If-Modified-Since");
            } catch (IllegalArgumentException var9) {
                ifModifiedSince = -1L;
            }

            if (ifModifiedSince < lastModified / 1000L * 1000L) {
                this.maybeSetLastModified(resp, lastModified);
                this.doGet(req, resp);
            } 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 = new Object[]{method};
        errMsg = MessageFormat.format(errMsg, errArgs);
        resp.sendError(501, errMsg);
    }

}

可以看到根据请求的方式,进行不同的方法调用;doGet/doPost/doHead -->调用到FrameworkServlet 的doGet/doPost/doHead -->DispatcherServlet 的doService 方法:

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
	  // 日志记录,进来 header 和 reqeust param 参数
	 this.logRequest(request);
    Map<String, Object> attributesSnapshot = null;
    if (WebUtils.isIncludeRequest(request)) {
        attributesSnapshot = new HashMap();
        Enumeration<?> attrNames = request.getAttributeNames();

        label116:
        while(true) {
            String attrName;
            do {
                if (!attrNames.hasMoreElements()) {
                    break label116;
                }

                attrName = (String)attrNames.nextElement();
            } while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));

            attributesSnapshot.put(attrName, request.getAttribute(attrName));
        }
    }
	// 存储相关属性对象
	// 存储容器对象
    request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
    request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
    request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
    request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource());
    if (this.flashMapManager != null) {
        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, new FlashMap());
        request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
    }

    RequestPath previousRequestPath = null;
    if (this.parseRequestPath) {
        previousRequestPath = (RequestPath)request.getAttribute(ServletRequestPathUtils.PATH_ATTRIBUTE);
        ServletRequestPathUtils.parseAndCache(request);
    }

    try {
		// 分发
        this.doDispatch(request, response);
    } finally {
        if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
            this.restoreAttributesAfterInclude(request, attributesSnapshot);
        }

        if (this.parseRequestPath) {
            ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request);
        }

    }

}

接下来进入 this.doDispatch(request, response); 方法:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

    try {
        try {
            ModelAndView mv = null;
            Exception dispatchException = null;

            try {
                processedRequest = this.checkMultipart(request);
                multipartRequestParsed = processedRequest != request;
				// 根据请求路径 获取 HandlerExecutionChain ,如果没有找到则报404
                mappedHandler = this.getHandler(processedRequest);
                if (mappedHandler == null) {
				      // 没有根据request 找到对应的handlerMapping 报404
                    this.noHandlerFound(processedRequest, response);
                    return;
                }
				// mappedHandler.getHandler() 有可能是bean 对象 也有可能是一个方法 所有使用object 接收
                HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                String method = request.getMethod();
                boolean isGet = HttpMethod.GET.matches(method);
                if (isGet || HttpMethod.HEAD.matches(method)) {
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }
				//  调用HandlerInterceptor的applyPreHandle方法,如果返回false,那么调用流程结束
				// 遍历所有的拦截器 调用 applyPreHandle 方法,返回true 则拦截器链路依次向后执行
				// 如果某一个拦截器applyPreHandle  返回false 则调用方法执行后的 afterCompletion 
				// 拦截器所有的 applyPreHandle 都通过 通过 返回true 则继续向下执行
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }
          		 // 调用adaper 中handle 的方法 得到ModelAndView 对象
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }
				// 设置默认视图名称
                this.applyDefaultViewName(processedRequest, mv);
        		 // 调用拦截器的 applyPostHandle
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            } catch (Exception var20) {
                dispatchException = var20;
            } catch (Throwable var21) {
                dispatchException = new NestedServletException("Handler dispatch failed", var21);
            }
 		   // 先渲染视图,渲染完毕调用拦截器的afterCompletion  方法
            this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
        } catch (Exception var22) {
            this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
        } catch (Throwable var23) {
            this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
        }

    } finally {
        if (asyncManager.isConcurrentHandlingStarted()) {
            if (mappedHandler != null) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
        } else if (multipartRequestParsed) {
            this.cleanupMultipart(processedRequest);
        }

    }
}

这里面需要注意的就是 this.getHandler(processedRequest); 对于handlerMapping 的选择,以及 this.getHandlerAdapter(mappedHandler.getHandler()); 根据handlerMapping 选择对应的 HandlerAdapter ;以及 ha.handle(processedRequest, response, mappedHandler.getHandler()); 使用HandlerAdapter 去调用方法并封装返回值结果;
如果是json 字符串则 得到的返回结果是null ,如果是页面则返回页面的视图;

对于HandlerAdapter 的获取,以及返回值的包装分别放到 二、 HandlerAdapter 的获取:进行介绍,下面看下对于 handlerMapping 的获取;

1.2 handlerMapping 的获取:

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        Iterator var2 = this.handlerMappings.iterator();
			// 依次遍历 handlerMappings 默认 会有 BeanNameUrlHandlerMapping  根据请求路径找bean,
			// RequestMappingHandlerMapping 根据请求路径找方法,
          // RouterFunctionMapping 根据请求路径找方法 3个 handlerMapping 
        while(var2.hasNext()) {
            HandlerMapping mapping = (HandlerMapping)var2.next();
			// 从中根据请求的request 获取到对应的类和方法
			// 将handler 进行HandlerExecutionChain  封装(如果有对方法的拦截则加入拦截器 )
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
				// 如果不为空则匹配到了
                return handler;
            }
        }
    }

    return null;
}

如果我们没有自定义 HandlerMapping 则会取到系统默认的BeanNameUrlHandlerMapping ,RequestMappingHandlerMapping ,RouterFunctionMapping 然后遍历通过其方法内部的 getHandler 方法 然后找到能够处理请求的HandlerMapping ,将其包装成HandlerExecutionChain 对象并返回,如果没有找到则返回null;

在这里需要注意的是默认的三个HandlerMapping bean 是分别对于不同情形http 的处理:

  • BeanNameUrlHandlerMapping : 根据请求路径找bean 对应 @Component(“/beanNameController”);
  • RequestMappingHandlerMapping : 根据请求路径找方法,对应 @GetMapping(“/test/attribute”);
  • RouterFunctionMapping :根据请求路径,到绑定的路由中寻找方法 对应 RouterFunctions 进行route 绑定;

二、HandlerAdapter 的获取:

HandlerAdapter 的作用比较重要,它即负责了对方法调用前请求参数的封装,又负责了对于返回值的封装;

2.1 HandlerAdapter 的选择:

this.getHandlerAdapter(mappedHandler.getHandler()) 根据 HandlerMapping 取回 对应的 HandlerAdapter :

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    if (this.handlerAdapters != null) {
		// 获取handlerAdapters  进行遍历
        Iterator var2 = this.handlerAdapters.iterator();

        while(var2.hasNext()) {
            HandlerAdapter adapter = (HandlerAdapter)var2.next();
            if (adapter.supports(handler)) {
				// 进行判断 调用不同的adaper 的 supports 方法 进行类型的判断
                return adapter;
            }
        }
    }

    throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

如果我们没有自定义 HandlerAdapter 那么就遍历默认的HandlerAdapter 根各个类中的 supports 方法 找到最匹配的HandlerAdapter,下面看下默认的4个HandlerAdapter 的作用:

  • 如果是@Controller中的某个方法,那么对应的就是RequestMappingHandlerAdapter
  • 如果是一个HttpRequestHandler对象(是一个bean),那么对应的就是HttpRequestHandlerAdapter
  • 如果是一个接口Controller对象(是一个bean,那么对应的就是SimpleControllerHandlerAdapter
  • 如果是一个HandlerFunction对象,那么对应的就是HandlerFunctionAdapter

如果是实现了Controller/HttpRequestHandler 接口则进入到对应的adaper 后最后调用handle 中的handleRequest 进行方法的调用;如果是HandlerFunction 则根据route 绑定的路由进行方法的调用;这两种都不需要对传入的参数进行解析和封装,所有下面具体看下我们项目中经常用到的,RequestMappingHandlerAdapter 对请求的参数进行解析,然后包装为方法所需要的数据类型;

2.2 请求参数的封装:

下面看下RequestMappingHandlerAdapter 下的 handleInternal 方法:是如何对参数进行解析的

protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
	// request 检查 可以自己定义RequestMappingHandlerAdapter  的bean  对请求的方式和session 做检验
    this.checkRequest(request);
    ModelAndView mav;

    if (this.synchronizeOnSession) {
		// session 同步锁,两个请求是同一个session 则发送过来的请求进行串行处理
        HttpSession session = request.getSession(false);
        if (session != null) {
            Object mutex = WebUtils.getSessionMutex(session);
            synchronized(mutex) {
                mav = this.invokeHandlerMethod(request, response, handlerMethod);
            }
        } else {
 			  //  方法调用
            mav = this.invokeHandlerMethod(request, response, handlerMethod);
        }
    } else {
        mav = this.invokeHandlerMethod(request, response, handlerMethod);
    }

    if (!response.containsHeader("Cache-Control")) {
        if (this.getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
            this.applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
        } else {
            this.prepareResponse(response);
        }
    }

    return mav;
}

this.invokeHandlerMethod(request, response, handlerMethod); 中进行了参数的解析,方法的调用,返回值的封装;

@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    ServletWebRequest webRequest = new ServletWebRequest(request, response);

    Object result;
    try {
        // 找出当前类和全局设置的  @InitBinder 并记录到集合中 对其请求参数进行转换 如 张三 转为 user 对象
        WebDataBinderFactory binderFactory = this.getDataBinderFactory(handlerMethod);
        // 根据当前对象生成 ModelFactory 取当前类的@SessionAttributes("name")
        // 定义的key 如name 生成Model 对象 并设置这些值 为Model  放入一些session key--value 的值
        ModelFactory modelFactory = this.getModelFactory(handlerMethod, binderFactory);
        ServletInvocableHandlerMethod invocableMethod = this.createInvocableHandlerMethod(handlerMethod);
      //  设置参数解析器(解析参数),设置返回值解析器(返回的数据进行转换,如转换json 返回页面)
      // 默认会提供一些参数的解析 会在adapter 完成一些默认的参数解析 ;对方方法的参数进行注解解析
        if (this.argumentResolvers != null) {
            invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
        }
        // 返回的类型解析器
        if (this.returnValueHandlers != null) {
            invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
        }
      // 设置binderFactory 执行方法时 需要使用它完成 参数类型的转换
        invocableMethod.setDataBinderFactory(binderFactory);
      // spring 用来解析方法参数的名称 使用ASM ,解析方法参数的名称
        invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
        // 每次执行方法都会 新建一个 ModelAndViewContainer  对象
        ModelAndViewContainer mavContainer = new ModelAndViewContainer();
         // 添加属性
        mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
		// mavContainer中已经有model对象了,现在进行初始化
		// 比如执行@ModeLAttribute的方法,把attribute添加到model中
		// 比如从session获取某些attribute添加到model中 (@SessionAttributes)
		// 注意:并没有把request parameter、request attribute添加到model中
        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()) {
            result = asyncManager.getConcurrentResult();
            mavContainer = (ModelAndViewContainer)asyncManager.getConcurrentResultContext()[0];
            asyncManager.clearConcurrentResult();
            LogFormatUtils.traceDebug(this.logger, (traceOn) -> {
                String formatted = LogFormatUtils.formatValue(result, !traceOn);
                return "Resume with async result [" + formatted + "]";
            });
            invocableMethod = invocableMethod.wrapConcurrentResult(result);
        }
		// 初始化model完成之后,对方法进行调用,方法返回的结果 也会放在 mavContainer中
        invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);
        if (!asyncManager.isConcurrentHandlingStarted()) {
		//  对封装的ModeLAndView进行处理,主要是判断当前请求是否进行了重定向,如果进行了重定向
		// 还会判断是否需要将FLashAttributes封装到新的请求中
            ModelAndView var15 = this.getModelAndView(mavContainer, modelFactory, webRequest);
            return var15;
        }

        result = null;
    } finally {
        webRequest.requestCompleted();
    }

    return (ModelAndView)result;
}

invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]); 进入 ServletInvocableHandlerMethod 下的 invokeAndHandle 方法:对于方法的调用:

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
	// 执行方法,并得到方法返回值,就是我们方法中的返回值,没有额外的处理,所以后面是要处理的
	// 但是这个方法中就涉及到参数绑定,比如要判断方法需要哪些参数,分别该传什么值,也是比较复杂的
    Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);
    this.setResponseStatus(webRequest);
    if (returnValue == null) {
        if (this.isRequestNotModified(webRequest) || this.getResponseStatus() != null || mavContainer.isRequestHandled()) {
            this.disableContentCachingIfNecessary(webRequest);
            mavContainer.setRequestHandled(true);
            return;
        }
    } else if (StringUtils.hasText(this.getResponseStatusReason())) {
        mavContainer.setRequestHandled(true);
        return;
    }

    mavContainer.setRequestHandled(false);
    Assert.state(this.returnValueHandlers != null, "No return value handlers");

    try {
	// 如果返回类型的是Map,那就用MapMethodProcessor处理
	// 如果返回类型的是ModelAndView,那就用ModeLAndViewMethodReturnValueHandler处理
	// 如果返回类型上有@ResponseBody,那就用RequestResponseBodyMethodProcessor处理,重点
	// 如果返回类型是String,那就用ViewNameMethodReturnValueHandler处理,重点
	// 等等,有很多种
        this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);
    } catch (Exception var6) {
        if (logger.isTraceEnabled()) {
            logger.trace(this.formatErrorForReturnValue(returnValue), var6);
        }

        throw var6;
    }
}

方法的执行:

@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
	// 获取方法的参数
    Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
    if (logger.isTraceEnabled()) {
        logger.trace("Arguments: " + Arrays.toString(args));
    }
	//  执行方法
    return this.doInvoke(args);
}

方法参数获取及参数封装:

protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
	//获取改方法的所有参数
    MethodParameter[] parameters = this.getMethodParameters();
    if (ObjectUtils.isEmpty(parameters)) {
        return EMPTY_ARGS;
    } else {
        Object[] args = new Object[parameters.length];

        for(int i = 0; i < parameters.length; ++i) {
			// 遍历方法参数
            MethodParameter parameter = parameters[i];
			// 方法的参数名称  解析
            parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
			//  获取方法参数的名字 providedArgs 是null  
            args[i] = findProvidedArgument(parameter, providedArgs);
            if (args[i] == null) {
				// 看是否有HandlerMethodArgumentResolver能不能解析当前参数
				// 只要有一个HandlerMethodArgumentResolver能解析,能就用它来解析
                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 var10) {
                    if (logger.isDebugEnabled()) {
                        String exMsg = var10.getMessage();
                        if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
                            logger.debug(formatArgumentError(parameter, exMsg));
                        }
                    }

                    throw var10;
                }
            }
        }
		// 方法参数的值数组 返回
        return args;
    }
}

this.resolvers.resolveArgument 方法解析参数:

@Nullable
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
	// 参数解析器
    HandlerMethodArgumentResolver resolver = this.getArgumentResolver(parameter);
    if (resolver == null) {
        throw new IllegalArgumentException("Unsupported parameter type [" + parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
    } else {
		// 解析参数并返回值 Mode类型对应的就是ModeTMethodProcessor
		// 参数前面有@RequestParam,对应的就是RequestParamMethodArgumentResolver
		// 参数前面有RequestAttribute,对应的就是RequestAttributeMethodArgumentResolverI
		// 如果参数没什么特殊的,默认对应的也是RequestParamMethodArgumentResolver
        return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
    }
}

解析器 对参数的值进行解析进入到 AbstractNamedValueMethodArgumentResolver 的 resolveArgument:

@Nullable
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
	// 获取参数的名字 如果使用@RequestParam (“name”)  string test
	// 定义了 则使用定义的,如果没有定义则使用 方法参数的名字
    NamedValueInfo namedValueInfo = this.getNamedValueInfo(parameter);
    MethodParameter nestedParameter = parameter.nestedIfOptional();
     // 占位符填充
    Object resolvedName = this.resolveEmbeddedValuesAndExpressions(namedValueInfo.name);
    if (resolvedName == null) {
        throw new IllegalArgumentException("Specified name must not resolve to null: [" + namedValueInfo.name + "]");
    } else {
         // 根据参数 得到对应的值

        Object arg = this.resolveName(resolvedName.toString(), nestedParameter, webRequest);
        if (arg == null) {
              //  如果根据参数没有获取到value 
            if (namedValueInfo.defaultValue != null) {
               // 如果 指定了默认值 进行解析
                arg = this.resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue);
            } else if (namedValueInfo.required && !nestedParameter.isOptional()) {
               // 如果没有默认值,则判断 required  为true 并且非Optional 类型则报错
                this.handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
            }
             // 对null 进行处理: 如果是boolean 类型则返回false 否则 抛异常
            arg = this.handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
        } else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
             // 如果参数是 空字符串 ,但是有默认值,使用默认值
            arg = this.resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue);
        }
          // 进行类型转换
        if (binderFactory != null) {
            WebDataBinder binder = binderFactory.createBinder(webRequest, (Object)null, namedValueInfo.name);

            try {
                // 类型转换 如将字符串 转换为 java 对象
                arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
            } catch (ConversionNotSupportedException var11) {
                throw new MethodArgumentConversionNotSupportedException(arg, var11.getRequiredType(), namedValueInfo.name, para	meter, var11.getCause());
            } catch (TypeMismatchException var12) {
                throw new MethodArgumentTypeMismatchException(arg, var12.getRequiredType(), namedValueInfo.name, parameter, var12.getCause());
            }

            if (arg == null && namedValueInfo.defaultValue == null && namedValueInfo.required && !nestedParameter.isOptional()) {
                 // 如果最后没有找到值,并且required  是true 则抛异常
                this.handleMissingValueAfterConversion(namedValueInfo.name, nestedParameter, webRequest);
            }
        }

        this.handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
        return arg;// 返回参数
    }
}

至此我们已经看到了mvc 是如何完成对参数的解析,这里进行下小结:

  • 获取参数列表,然后遍历,对每个参数筛选出能够解析这个参数的解析器,判断参数前的注解,参数的类型,名字 得到改参数的名字 传入解析器;
  • 解析器中根据 名字 进行参数值的获取 ,获取完成后转为 string ;
  • 将String 参数值进行类型转换,转换完成进行返回;
  • 放入参数进行方法调用;

2.3 请求结果的封装:

this.returnValueHandlers.handleReturnValue 通过返回值 以及返回值的类型 来筛选 返回值处理器的方法,然后进行调用;

public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
	// 根据返回值和返回值类型 筛选出合适的 方法返回值处理器器
  HandlerMethodReturnValueHandler handler = this.selectHandler(returnValue, returnType);
    if (handler == null) {
        throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
    } else {
        handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
    }
}
``

this.selectHandler(returnValue, returnType) 筛选方法返回值解析器:

```java
@Nullable
private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
    boolean isAsyncValue = this.isAsyncReturnValue(value, returnType);
    Iterator var4 = this.returnValueHandlers.iterator();

    HandlerMethodReturnValueHandler handler;
    do {
        do {
            if (!var4.hasNext()) {
                return null;
            }

            handler = (HandlerMethodReturnValueHandler)var4.next();
        } while(isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler));
    } while(!handler.supportsReturnType(returnType));

    return handler;
}

这里会先判断 是否又被@ResponseBody 注解标注,有则说明返回json 是字符串,需要用json字符串的处理器处理;没有则说明是一个页面,需要用到其它的处理器处理;所以接下来分为两类进行分析;

1) 返回的是json字符串:
此种情况 会使用 RequestResponseBodyMethodProcessor 中的 handleReturnValue 进行处理:

public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
	// 先进行下标记,改请求已经完成,不需要额外的去找页面,和渲染;

 	 mavContainer.setRequestHandled(true);
 	 // 获取请求的 输出对象:
    ServletServerHttpRequest inputMessage = this.createInputMessage(webRequest);
    ServletServerHttpResponse outputMessage = this.createOutputMessage(webRequest);
    // 将结果写出到body中
    this.writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}

2) 返回的是页面:
在获取到请求的处理结果之后,会进入到DispatcherServlet 下的processDispatchResult 对于页面进行处理,此时 ModelAndView 非空;

 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) {
             this.logger.debug("ModelAndViewDefiningException encountered", exception);
             mv = ((ModelAndViewDefiningException)exception).getModelAndView();
         } else {
             Object handler = mappedHandler != null ? mappedHandler.getHandler() : null;
             mv = this.processHandlerException(request, response, handler, exception);
             errorView = mv != null;
         }
     }

     if (mv != null && !mv.wasCleared()) {
     	// 对视图解析
         this.render(mv, request, response);
         if (errorView) {
             WebUtils.clearErrorRequestAttributes(request);
         }
     } else if (this.logger.isTraceEnabled()) {
         this.logger.trace("No view rendering, null ModelAndView returned.");
     }

     if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
         if (mappedHandler != null) {
             mappedHandler.triggerAfterCompletion(request, response, (Exception)null);
         }

     }
 }

通过render 方法,对视图进行解析,会拿到视图文件的路径 然后返回给到浏览器;

三、 扩展:

3.1 常见 Request 的参数解析:

1)路径的解析:

@GetMapping("/{id}/{name}")
@ResponseBody
 public String testGet(HttpServletRequest request, @PathVariable("name") String name, @PathVariable("id") String id) {
     System.out.println("name = " + name);
     System.out.println("id = " + id);
     return "success";
 }

解析请求 后设置map key 为{“xxx”} 中对应的xxx ,value 对应的值;在解析请求参数时 通过PathVariable定义的名称 从map 中进行获取;
2) Request 参数解析:

 @GetMapping("/test")
@ResponseBody
public String testGet1(@RequestParam("test") String test) {
    System.out.println("test = " + test);
    return "success";
}

@GetMapping("/test/map")
@ResponseBody
public Map testGet2(@RequestParam Map map) {
    System.out.println("map = " + map);
    Map<String, Object> oneMap = new HashMap<>();
    oneMap.put("name", "lisi");
    return oneMap;
}

参数类型是map 则,解析参数后都放入到map 中;
参数类型是基本的数类型 ,按照RequestParam 定义的名称去获取参数值,如果RequestParam没有设置则根据 参数名称去获取;

3)RequestAttribute 参数:

@GetMapping("/test/attribute")
@ResponseBody
 public String testGet3(@RequestAttribute String name) {
     System.out.println("name = " + name);
     return "success";
 }

获取所有的请求attribute 遍历根据名称获取;

4)RequestHeader 参数:

@GetMapping("/test/header")
@ResponseBody
public String testGet4(@RequestHeader("token") String header) {
    System.out.println("header = " + header);
    return "success";
}

获取所有的请求头 ,然后遍历 根据 名称去获取;

5) ResponseBody 参数:

@PostMapping("post")
@ResponseBody
 public String testPost1(@RequestBody Map map) {
     System.out.println("map = " + map);
     return "success";
 }

ResponseBody 获取request 的body 流,然后获取转换器,然后通过转换器对body 内容进行转换;


总结

本文主要对DispatcherServlet 的请求分发,请求参数,请求结果的包装返回 在原码层面进行了流程上的分析;

文章来源:https://blog.csdn.net/l123lgx/article/details/135060868
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。