- HandlerMapping中找到能处理请求的Handler(Controller.method())
- 为当前Handler 找一个适配器 HandlerAdapter; RequestMappingHandlerAdapter
- 适配器执行目标方法并确定方法参数的每一个值
1、HandlerAdapter
第一个:支持方法上标注的@RequestMapping
第二个:支持函数式编程
.....
2、执行目标方法
2.1 DispatcherServlet -- doDispatch
// Actually invoke the handler.
//DispatcherServlet -- doDispatch
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
2.2 RequestMappingHandlerAdapter--handleInternal
ha.handle又会调用handleInternal方法(这个过程写在适配器继承的抽象类的handle方法中)
//AbstractHandlerMethodAdapter
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return this.handleInternal(request, response, (HandlerMethod)handler);
}
=====RequestMappingHandlerAdapter类中的handleInternal方法==========
mav = invokeHandlerMethod(request, response, handlerMethod); //执行目标方法
=====invokeHandlerMethod的关键代码===========================
ServletInvocableHandlerMethod invocableMethod = this.createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {//设置参数解析器
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {//设置返回值处理器
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
//创建了ModelAndViewContainer
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);
设置参数解析器:
参数解析器:确定将要执行的目标方法的每个参数的值是什么
SpringMVC目标方法能写多少种参数类型,取决于参数解析器。
supportParameter:当前解析器是否支持这种参数
支持就调用resolveArgument
设置返回值处理器:
2.3 invokeAndHandle
此方法内部完成了请求参数解析、方法执行、返回值处理和内容协商。本文只写到了请求参数解析,返回值处理以及内容协商在数据响应这篇文章中。
invocableMethod为ServletInvocableHandlerMethod对象
invokeForRequest:真正执行目标方法
=====ServletInvocableHandlerMethod中invokeAndHandle方法中的核心代码==============
Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);
this.setResponseStatus(webRequest);
2.4 invokeForRequest
this.doInvoke(args),解析完成参数之后,反射执行目标方法。
=====invokeForRequest方法=====
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));
}
//反射执行Controller中的方法
return this.doInvoke(args);
}
2.5 getMethodArgumentValues:确定每个参数的值
上一步获取参数值的具体代码
============InvocableHandlerMethod类==========================
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
MethodParameter[] parameters = getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
}
//核心代码,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;
}
//1、遍历26个参数解析器是否支持parameter类型的参数
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
//2、开始解析参数值
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;
}
上图代码的细节:
2.5.1 遍历判断所有参数解析器是否支持当前参数
找到能解析的解析器,加入缓存,方便下一步解析该参数时直接获取。
======if (!this.resolvers.supportsParameter(parameter))底层实现=====
@Nullable
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
if (resolver.supportsParameter(parameter)) {
result = resolver;
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}
2.5.2 解析参数的值
解析请求的值给到参数。
======args[i] = this.resolvers.resolveArgument======
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 {
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}
}
=====最终调用AbstractNamedValueMethodArgumentResolver的resolveArgument方法=====
3、目标方法执行完成
将所有的数据(复杂参数Map、Model、request等类型)都放在 ModelAndViewContainer;包含要去的页面地址View。还包含Model数据。复杂参数解析原理
4、处理派发结果
doDispatch中:processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
在processDispatchResult中的render渲染方法中,调用了renderMergedOutputModel。在下一个界面渲染成功之前,就将所有的复杂参数的值传进了request请求域中。
renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
InternalResourceView:
@Override
protected void renderMergedOutputModel(
Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Expose the model object as request attributes.
exposeModelAsRequestAttributes(model, request);
// Expose helpers as request attributes, if any.
exposeHelpers(request);
// Determine the path for the request dispatcher.
String dispatcherPath = prepareForRendering(request, response);
// Obtain a RequestDispatcher for the target resource (typically a JSP).
RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
if (rd == null) {
throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
"]: Check that the corresponding file exists within your web application archive!");
}
// If already included or response already committed, perform include, else forward.
if (useInclude(request, response)) {
response.setContentType(getContentType());
if (logger.isDebugEnabled()) {
logger.debug("Including [" + getUrl() + "]");
}
rd.include(request, response);
}
else {
// Note: The forwarded resource is supposed to determine the content type itself.
if (logger.isDebugEnabled()) {
logger.debug("Forwarding to [" + getUrl() + "]");
}
rd.forward(request, response);
}
}
renderMergedOutputModel中调用exposeModelAsRequestAttributes
暴露模型作为请求域属性
// Expose the model object as request attributes.
exposeModelAsRequestAttributes(model, request);
protected void exposeModelAsRequestAttributes(Map<String, Object> model,
HttpServletRequest request) throws Exception {
//model中的所有数据遍历挨个放在请求域中
model.forEach((name, value) -> {
if (value != null) {
request.setAttribute(name, value);
}
else {
request.removeAttribute(name);
}
});
}