SpringMVC的请求响应流程及参数类型自动转换

纵观全局

我们先进入DIspatchServlet.doDispatch(),我们分析其调用过程的主要方法如下:

// 根据请求拿到具体的处理器方法HandlerMethod并获取拦截器包装成HandlerExecutionChain
mappedHandler = getHandler(processedRequest);
// 根据HandlerMethod得到对应的HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// HandlerAdapter调用HandlerMethod,这里会发生参数的自动转换
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

获取HandlerExecutionChain

在这里插入图片描述
如上图所示,SpringMVC中内置了8个handlerMappings处理器,用于不同类型的映射处理,使用迭代的方式一个个的去处理,不支持的实现在解析时会返回null
我们使用的是@RequestMapping因此对应的是RequestMappingHandlerMapping这个实现,这个实现的getHandler方法使用的是父类的方法,以下删除了部分代码,仅保留核心相关实现

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		Object handler = getHandlerInternal(request);
		if (handler == null) {
			handler = getDefaultHandler();
		}
		if (handler == null) {
			return null;
		}
		HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
		return executionChain;
}
  1. getHandlerInternal()用于根据请求路径查找匹配的HandlerMethod,SpringMVC启动时会解析所有RequestMapping的请求路径注册到mappingRegistry
    在这里插入图片描述
  2. getHandlerExecutionChain()用于根据请求路径查找符合条件的拦截器
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
		HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
				(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

		String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
		for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
			if (interceptor instanceof MappedInterceptor) {
				MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
				if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
					chain.addInterceptor(mappedInterceptor.getInterceptor());
				}
			}
			else {
				chain.addInterceptor(interceptor);
			}
		}
		return chain;
	}

构建包装了HandlerMethodHandlerExecutionChain,遍历注册的拦截器并进行匹配,如果匹配将加入到HandlerExecutionChain
最后将HandlerExecutionChain返回

获取HandlerAdapter

我们知道SpringMVC通过HandlerAdapter来调用具体的处理器,从而实现与具体处理器的解耦,因此需要根据处理器类型来拿到类型匹配的HandlerAdapter
在这里插入图片描述
同样是进行一个迭代的匹配,这里使用的是RequestMappingHandlerAdapter这个实现,它的support方法为

public final boolean supports(Object handler) {
	//即判断handler是否是一个HandlerMethod类型,后面的supportsInternal固定返回True
		return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
	}

调用HandlerMethod

根据调用链一路来到invokeHandlerMethod,删除了其他代码

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);
			invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
			invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
			invocableMethod.setDataBinderFactory(binderFactory);
			invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
			
			invocableMethod.invokeAndHandle(webRequest, mavContainer);
		
			return getModelAndView(mavContainer, modelFactory, webRequest);
		}
		finally {
			webRequest.requestCompleted();
		}
	}

我们注意到这里有四个方法

			invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
			invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
			invocableMethod.setDataBinderFactory(binderFactory);
			invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

他们就是负责处理参数和结果类型转换的,SpringMVC内置了多种参数类型转换和结果类型转换的处理器
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这里将处理器设置进去后,进入invocableMethod.invokeAndHandle(webRequest, mavContainer);开始调用

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
		// 这里会进行入参类型转换
		Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
		// 这里会进行返回类型转换
		this.returnValueHandlers.handleReturnValue(
				returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
		
	}
  1. 入参转换
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {

		Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
		Object returnValue = doInvoke(args);
		return returnValue;
	}
private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
		MethodParameter[] parameters = getMethodParameters();
		Object[] args = new Object[parameters.length];
		for (int i = 0; i < parameters.length; i++) {
			MethodParameter parameter = parameters[i];
			parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
			args[i] = resolveProvidedArgument(parameter, providedArgs);
			if (args[i] != null) {
				continue;
			}
			if (this.argumentResolvers.supportsParameter(parameter)) {
				try {
					args[i] = this.argumentResolvers.resolveArgument(
							parameter, mavContainer, request, this.dataBinderFactory);
					continue;
				}
			}
		}
		return args;
	}

argumentResolversHandlerMethodArgumentResolverComposite类型,内部封装了37个具体的参数解析器,属于设计模式中的组合模式。
这里同样使用组合模式对所有的解析器进行迭代,如果支持参数解析则进行解析并返回解析后的参数值。
2. 返回值转换
与入参转换流程基本一致,组合模式遍历选择处理器并进行处理

public void handleReturnValue(Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

		HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
		handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
	}

	private HandlerMethodReturnValueHandler selectHandler(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;
	}

由于是Rest模式,因此这里的类型处理器为RequestResponseBodyMethodProcessor,其实现为

public void handleReturnValue(Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
			throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

		mavContainer.setRequestHandled(true);
		ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
		ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);

		// Try even with null return value. ResponseBodyAdvice could get involved.
		writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
	}

注意这里的writeWithMessageConverters,这里会进行HttpMessageConverter的转换将返回值再转换为对应的格式
在这里插入图片描述
迭代所有消息转换器,判断是否支持请求的媒体类型来进行转换处理
在这里插入图片描述
在这里插入图片描述

拦截器调用

在这里插入图片描述
如图在DIspatcherServlet.doService方法中,通过

mappedHandler.applyPreHandle(processedRequest, response)
mappedHandler.applyPostHandle(processedRequest, response, mv);
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); --> mappedHandler.triggerAfterCompletion(request, response, null);

三个方法来调用三中拦截器

总结

至此,一个大概的请求流程就走完了,这里对视图等没有讲解,仅针对最基本的Rest流程进行讲解

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值