上一篇文章SpringMVC 源码分析(六)我们主要看了DispatcherServlet如何根据我们的请求路径去寻找对应的执行器,本篇我们主要看下如何通过执行器执行到我们的Controller方法,即ha.handle方法。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
//检查是否是MultipartContent的请求,如果是的话就会转换为MultipartHttpServletRequest
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
//为本次request请求寻找一个具体的Handler,并封装成一个执行器链
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 为当前的handler寻找一个具体的HandlerAdapter,因为HandlerMapping有多个实现类,存储的Handler类型也各不相同
// 需要适配器来提供一个统一供外部调用的方法入口
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
//如果支持last-modified,则处理
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//拦截器前置处理
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 真正调用Controller的地方
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//视图转换
applyDefaultViewName(processedRequest, mv);
//拦截器后置处理
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
//处理程序调用的结果,即ModelAndView或要解析为ModelAndView的异常
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
进入hadle方法后,发现调用的是父类AbstractHandlerMethodAdapter的handle方法,没有什么实现,直接调用了handleInternal方法。
![](https://i-blog.csdnimg.cn/blog_migrate/d1cac3cb694c920cc9247a69993a6e84.png)
继续进入handleInternal分析,这里只是简单的校验,最后调用invokeHandlerMethod方法
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
//校验,请求方式是否支持,是否需要验证Session
checkRequest(request);
// synchronizeOnSession可配置参数,如果指定为true,服务器只分配一个线程给该用户,确保安全,默认为false
// 一般不会走这里
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 {
// synchronizeOnSession为false时,直接执行调用
mav = invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}
return mav;
}
invokeHandlerMethod主要设置一些调用Controller处理方法前所需的组件,例如设置WebDataBinderFactory,主要用来生成WebDataBinder对象,WebDataBinder的作用是将请求的参数值设置到对象的属性中进行绑定,还有请求参数解析器组件argumentResolvers等等,都是为最终调用Controller处理方法做准备,我们直接看执行调用invokeAndHandle方法。
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
//封装request,response为ServletWebRequest
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
//binderFactory为工厂模式,主要用来生成WebDataBinder对象,WebDataBinder的作用是将请求的参数值设置到对象的属性中进行绑定。
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
// argumentResolvers内置了HandlerMethodArgumentResolver请求参数解析器,用于将请求参数按照接口接收的类型进行封装,
// 例如使用@RequestBody注解的解析器RequestResponseBodyMethodProcessor,使用@RequestParam注解的解析器RequestParamMethodArgumentResolver等
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
//returnValueHandlers内置了HandlerMethodReturnValueHandler返回参数处理器,用于响应数据的封装处理
//例如ModelAndView、String、Map、@ResponseBody标记的方法等等,同请求参数解析器一样都有对应的处理器来处理
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
//设置binderFactory为工厂
invocableMethod.setDataBinderFactory(binderFactory);
//设置参数名解析器,主要用于HandlerMethodArgumentResolver请求参数解析器解析的值与名字映射,最终通过WebDataBinder进行关联
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);
//用于管理异步请求处理的中心类,主要用作SPI,通常不由应用程序类直接使用,可以直接跳过
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);
}
//执行调用
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
//返回视图
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
进入invokeAndHandle方法后,首先第一行invokeForRequest就是调用Controller方法,后面的都是返回后的处理,暂时先不看。
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) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
disableContentCachingIfNecessary(webRequest);
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(formatErrorForReturnValue(returnValue), ex);
}
throw ex;
}
}
进入到invokeForRequest方法中,可以看到首先是先解析请求参数值并绑定到对应的参数上,最后再调用doInvoke方法,doInvoke是通过反射最终调用到Controller方法的,我们先看解析请求参数方法:getMethodArgumentValues。
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);
}
进入到getMethodArgumentValues方法中,首先是先获取Controller对应方法的参数列表,参数列表在应用启动的时候已经处理好了,这个时候是没有值的,所以需要然后for循环参数列表进行一一赋值。参数的解析并赋值调用的是这个方法:this.resolvers.resolveArgument。
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//获取Controller对应的方法所有参数,该部分在程序启动时就已经解析好了
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 {
//解析参数并赋值
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;
}
进入到resolveArgument方法中,首先调用getArgumentResolver获取一个合适的解析器,我Demo示例的Controller是通过@RequestBody来传递参数的,所以匹配的就是RequestResponseBodyMethodProcessor,还有很多专门的解析器,比如@RequestParam注解的解析器RequestParamMethodArgumentResolver等,感兴趣的话可以去深入了解下。
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
//获取一个支持HandlerMethodArgument解析的的解析器,
//我们Controller处理方法使用@RequestBody接受请求,所以对应RequestResponseBodyMethodProcessor
HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
if (resolver == null) {
throw new IllegalArgumentException("Unsupported parameter type [" +
parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
}
//RequestResponseBodyMethodProcessor开始解析
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}
有人会问为啥会返回RequestResponseBodyMethodProcessor而不是其他的呢,其实内部实现逻辑就是遍历解析器集合,然后找到支持该参数解析的就返回,我们看下RequestResponseBodyMethodProcessor的supportsParameter实现发现该类支持解析@RequestBody注解,所以就返回RequestResponseBodyMethodProcessor。
![](https://i-blog.csdnimg.cn/blog_migrate/73a7b71bb0034617bccf7338b4277014.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a5d7f445635b1b4df98dac85d37352e1.png)
接下来就是解析resolveArgument,RequestResponseBodyMethodProcessor解析由readWithMessageConverters方法处理的,主要是读取request的输入流,最后通过fastjson来完成参数与参数值的封装。我们简单列出代码的调用路径
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
//获取parameter
parameter = parameter.nestedIfOptional();
//parameter类型转换及赋值,parameter.getNestedGenericParameterType()在启动的时注册处理器映射时
//由AbstractHandlerMethodMapping#createHandlerMethod设置
Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
//获取参数名
String name = Conventions.getVariableNameForParameter(parameter);
if (binderFactory != null) {
WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
if (arg != null) {
validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
}
}
if (mavContainer != null) {
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
}
}
//是否需要Optional包装,判断是否是Optional类型,是的话进行包装
return adaptArgumentIfNecessary(arg, parameter);
}
readWithMessageConverters方法完成了根据@RequestBody类型赋值,进入该方法可以看到先将我们的请求request再次进行包装为ServletServerHttpRequest类,后面读取请求值的输入流就是通过该类来获取,最终调用重载方法readWithMessageConverters完成参数值的解析与封装,再底层就不分析了,有兴趣的话可以继续深入了解。
protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,
Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
Assert.state(servletRequest != null, "No HttpServletRequest");
//将request进行包装,提供额外的功能方法等
ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);
//解析参数值封装到参数中
Object arg = readWithMessageConverters(inputMessage, parameter, paramType);
if (arg == null && checkRequired(parameter)) {
throw new HttpMessageNotReadableException("Required request body is missing: " +
parameter.getExecutable().toGenericString(), inputMessage);
}
return arg;
}
同理,GET请求里的@RequestParam解析类RequestParamMethodArgumentResolver也是读取request的输入流进行参数的绑定,这一部分如果感兴趣也可以深入了解。
完成了参数解析后,我们再回到准备调用Controller方法的地方:
![](https://i-blog.csdnimg.cn/blog_migrate/5c34e9abad74cf32d8fe05e1ffc2b230.png)
将解析好的参数传入doInvoke方法中,我们再看下doInvoke方法实现,其实就是获取到@RequestMapping当时绑定的方法,然后进行反射调用,最终调用的是java.lang.reflect.Method类的invoke方法:
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
//获取对应Controller对应的Method方法进行调用执行
return getBridgedMethod().invoke(getBean(), args);
}
catch (IllegalArgumentException ex) {
assertTargetBean(getBridgedMethod(), getBean(), args);
String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
throw new IllegalStateException(formatInvokeError(text, args), ex);
}
catch (InvocationTargetException ex) {
// Unwrap for HandlerExceptionResolvers ...
Throwable targetException = ex.getTargetException();
if (targetException instanceof RuntimeException) {
throw (RuntimeException) targetException;
}
else if (targetException instanceof Error) {
throw (Error) targetException;
}
else if (targetException instanceof Exception) {
throw (Exception) targetException;
}
else {
throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException);
}
}
}
进入invoke方法最终调用ma.invoke(obj, args),
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
}
}
MethodAccessor ma = methodAccessor; // read volatile
if (ma == null) {
ma = acquireMethodAccessor();
}
return ma.invoke(obj, args);
}
当ma.invoke发起调用的时候,就会到我们Controller的具体方法进行执行
![](https://i-blog.csdnimg.cn/blog_migrate/e7bc6efc01010726fdd83a5233f7f8db.png)
好了,SpringMVC发起调用流程结束了,下一篇文章我们在一起看SpringMVC在调用完成后的结果处理