今天来聊聊spring-mvc是如何来执行Controller中的method的。
spring-mvc默认的HandlerAdapter是RequestMappingHandlerAdapter,
DispatcherServlet将处理逻辑交由HandlerAdapter,而HandlerAdapter,由交给ServletInvocableHandlerMethod来invokeAndHandle.
requestMappingMethod.invokeAndHandle(webRequest, mavContainer);
跟踪源代码
public void invokeAndHandle(ServletWebRequest webRequest,
ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
if (returnValue == null) {
if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(this.responseReason)) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
try {
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
}
throw ex;
}
}
主要是Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs)
整个执行过程都在这步代码中,那么到底是如何处理的。
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
StringBuilder sb = new StringBuilder("Invoking [");
sb.append(getBeanType().getSimpleName()).append(".");
sb.append(getMethod().getName()).append("] method with arguments ");
sb.append(Arrays.asList(args));
logger.trace(sb.toString());
}
Object returnValue = doInvoke(args);
if (logger.isTraceEnabled()) {
logger.trace("Method [" + getMethod().getName() + "] returned [" + returnValue + "]");
}
return returnValue;
}
我们知道利用反射来执行一个方法的时候,我们需要入参。那么Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
就是获取Controller的入参。也就是需要用到参数解析了,spring-mvc为我们提供了强大的数据绑定机制,
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);
GenericTypeResolver.resolveParameterType(parameter, getBean().getClass());
args[i] = resolveProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
//argumentResolvers是RequestMappingHandlerAdapter传过来的参数解析器。
//这里是循环遍历,查找能够解析该参数的
if (this.argumentResolvers.supportsParameter(parameter)) {
try {
args[i] = this.argumentResolvers.resolveArgument(
parameter, mavContainer, request, this.dataBinderFactory);
continue;
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(getArgumentResolutionErrorMessage("Error resolving argument", i), ex);
}
throw ex;
}
}
if (args[i] == null) {
String msg = getArgumentResolutionErrorMessage("No suitable resolver for argument", i);
throw new IllegalStateException(msg);
}
}
return args;
}
下一步就是找到参数解析器来解析该参数了 。spring-mvc为我们提供了23种参数解析器。这里就不一一介绍了,
得到参数之后,然后调用Object returnValue = doInvoke(args);
得到执行的返回结果。
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
下面的处理逻辑:如果是视图,就调用ViewResolver,render出jsp,如何是JSON。则用response写到应用。