请求处理过程3-解析参数

请求进来,先找到能处理的controller,再找到处理器适配器,完成controller方法的调用。
调用方法的第一步就是先要获取方法参数,这里也是请求参数。然后处理返回结果,再然后渲染页面。

1.handle方法

调用刚刚找到的RequestMappingHandlerAdapter的handle方法,完成请求的执行。在这里插入图片描述

2.handleInternal方法

然后调用RequestMappingHandlerAdapter类的handleInternal方法,
这里有三个步骤
1.对请求进行检查,
2.然后调用invokeHandlerMethod方法返回ModelAndView类型的对象,
3.然后封装response。

	@Override
	protected ModelAndView handleInternal(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    
    

		ModelAndView mav;
		//第一步
		checkRequest(request);

		// Execute invokeHandlerMethod in synchronized block if required.
		if (this.synchronizeOnSession) {
    
    
			HttpSession session = request.getSession(false);
			if (session != null) {
    
    
				Object mutex = WebUtils.getSessionMutex(session);
				synchronized (mutex) {
    
    
					mav = invokeHandlerMethod(request, response, handlerMethod);
				}
			}
			else {
    
    
				// No HttpSession available -> no mutex necessary
				mav = invokeHandlerMethod(request, response, handlerMethod);
			}
		}
		else {
    
    
			//第二步
			// No synchronization on session demanded at all...
			mav = invokeHandlerMethod(request, response, handlerMethod);
		}
		//第三步
		if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
    
    
			if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
    
    
				applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
			}
			else {
    
    
				prepareResponse(response);
			}
		}
		//返回视图模型对象
		return mav;
	}

3.invokeHandlerMethod方法

这个方法主要是获取argumentResolvers 参数解析器,returnValueHandlers 返回值处理器,配置ModelAndViewContainer视图容器,然后反射调用controller方法。

	@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) {
    
    
				//设置参数解析器,大概有26个,在requestMappingHandlerAdapter初始化时候加载的。
				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);
			}
			//反射调用controller方法
			invocableMethod.invokeAndHandle(webRequest, mavContainer);
			if (asyncManager.isConcurrentHandlingStarted()) {
    
    
				return null;
			}

			return getModelAndView(mavContainer, modelFactory, webRequest);
		}
		finally {
    
    
			webRequest.requestCompleted();
		}
	}

4.invokeAndHandle方法

主要看这个方法,这个方法执行完, 返回值就有了,解析方法参数(请求参数)肯定也在这里。
在这里插入图片描述

5.invokeForRequest方法

进来发现这里有个getMethodArgumentValues,这一看就是处理参数的。
处理完参数调用doInvoke执行最后的逻辑,这个到返回值解析时再看。

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

6.getMethodArgumentValues方法

获取到方法的参数,然后遍历,去请求中找对应的参数,这个功能是参数解析器完成的。找参数解析器是根据注解。解析参数是根据resolveArgument方法

	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 {
    
    
				//调用参数解析器的resolveArgument方法,解析参数
				args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
			}
			catch (Exception ex) {
    
    
				// 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;
	}

获取到的两个参数
在这里插入图片描述

对应controller中的参数
在这里插入图片描述

7.resolveArgument方法

获取到参数解析器,我的第一个参数是HttpServlerRequest,所以调用HttpServlerRequestMethodArgumentResovler来处理这个参数。
在这里插入图片描述

8.继续调用resolveArgument方法

	@Override
	@Nullable
	public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
    
    
		//参数名字
		NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
		MethodParameter nestedParameter = parameter.nestedIfOptional();

		Object resolvedName = resolveStringValue(namedValueInfo.name);
		if (resolvedName == null) {
    
    
			throw new IllegalArgumentException(
					"Specified name must not resolve to null: [" + namedValueInfo.name + "]");
		}
		//根据名字解析值
		Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
		if (arg == null) {
    
    
			if (namedValueInfo.defaultValue != null) {
    
    
				arg = resolveStringValue(namedValueInfo.defaultValue);
			}
			else if (namedValueInfo.required && !nestedParameter.isOptional()) {
    
    
				handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
			}
			arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
		}
		else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
    
    
			arg = resolveStringValue(namedValueInfo.defaultValue);
		}

		if (binderFactory != null) {
    
    
			WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
			try {
    
    
				arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
			}
			catch (ConversionNotSupportedException ex) {
    
    
				throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(),
						namedValueInfo.name, parameter, ex.getCause());
			}
			catch (TypeMismatchException ex) {
    
    
				throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(),
						namedValueInfo.name, parameter, ex.getCause());

			}
		}

		handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);

		return arg;
	}

9.resolveName方法

目前已经获得了方法的参数,现在需要从请求中获取这个参数对应的值,然后赋值给这个参数。就是用的下面这个方法。

	@Nullable
	protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
    
    
		Map<String, String> uriTemplateVars = (Map<String, String>) request.getAttribute(
				HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);
		return (uriTemplateVars != null ? uriTemplateVars.get(name) : null);
	}

就是定义了一个map,然后调用request.getAttribute方法,可以看出URI_TEMPLATE_VARIABLES_ATTRIBUTE的值,而且是在HandlerMapping中定义的。看来是在相关方法中将这个值setAttribute的,存的应该也是一个map。第二个常量SCOPE_REQUEST代表request,还有个与之对应的是SCOPE_SESSION。
在这里插入图片描述
从头仿真看看是什么时候将这个请求携带的参数值setAttribute的。
最终发现是在handleMatch方法中,怎么最终发现的? 一个断点一个断点的试,一直看着request中的attribute的值,慢慢就找到了~~
在这里插入图片描述
然后回头看了下请求处理过程第一篇,发现handleMatch方法是在返回最佳controller之前的一个方法。
在这里插入图片描述
至此搞懂了@PathVariable这种路径传参的方式(上图中请求没这个注解,为了测试resolveName方法加的)。可是参数解析器还有20多个吧。哎 ,加油~~
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_46666822/article/details/124769880