本文介绍DispatcherServlet的请求转发流程,包括:
- 从HandlerMapping集查找可以处理该请求的执行器链
- 从HandlerAdapter集查找支持当前请求的Adapter
- 执行拦截器preHandle方法
- 处理请求接收ModelAndView返回值
- 执行拦截器postHandle方法
- 处理接口返回值
- 执行拦截器afterCompletion方法
doService方法
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
// Keep a snapshot of the request attributes in case of an include,
// to be able to restore the original attributes after the include.
// 当前请求发生转发即forward操作,需要保存请求的当前状态,通常不需要
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap<>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// Make framework objects available to handlers and view objects.
// 设置一些Attribute,比如ApplicationContext,可以在Controller里面使用request.getAttribute出来使用
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
if (this.flashMapManager != null) {
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
}
try {
// 分发请求
doDispatch(request, response);
} finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
doDispatch方法
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 {
// 封装Multipart请求
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 1. 从HandlerMapping集查找可以处理该请求的执行器链
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
// 404
noHandlerFound(processedRequest, response);
return;
}
// 2. 从HandlerAdapter集查找支持当前请求的Adapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
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;
}
}
// 3. 执行拦截器preHandle方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 4. 处理请求接收ModelAndView返回值
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
// 5. 执行拦截器postHandle方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception ex) {
dispatchException = ex;
} catch (Throwable err) {
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// 6. 处理接口返回值
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
} catch (Exception ex) {
// 7. 执行拦截器afterCompletion方法
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);
}
}
}
}
流程:
- 从HandlerMapping集查找可以处理该请求的执行器链
- 从HandlerAdapter集查找支持当前请求的Adapter
- 执行拦截器preHandle方法
- 处理请求接收ModelAndView返回值
- 执行拦截器postHandle方法
- 处理接口返回值
- 如果有异常,则处理异常
- 渲染ModelAndView
- 执行拦截器afterCompletion方法
- 出现异常时,执行拦截器afterCompletion方法
流程分析
查找执行器链
入口
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
前文介绍,handlerMappings封装着所有的HandlerMapping:
其中RequestMappingHandlerMapping封装着所有的Controller接口处理方法映射,《扫描Controller创建HandlerMapping流程》已做过分析,此处介绍一下他的getHandler方法实现。
其余的几个HandlerMapping实现类后续会有专门章节介绍。
RequestMappingHandlerMapping的getHandler方法
方法实现在AbstractHandlerMapping类,使用了模板方法模式:
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 模板方法,实现代码在AbstractHandlerMethodMapping类
// 本文分析场景下返回的是HandlerMethod对象
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
// 封装执行器
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
// 略
return executionChain;
}
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 解析请求uri
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
request.setAttribute(LOOKUP_PATH, lookupPath);
this.mappingRegistry.acquireReadLock();
try {
// 从mappingRegistry查找HandlerMethod
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
// 这个步骤使用xxController组件名到spring容器查找对应的Controller组件Bean
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
} finally {
this.mappingRegistry.releaseReadLock();
}
}
查找HandlerMethod
protected HandlerMethod lookupHandlerMethod(
String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
// 1. 查找直接匹配的、不含有path参数、不含有请求参数的RequestMappingInfo映射集
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
// 2. 从所有RequestMappingInfo映射集查找
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}
// 3. 如果查找到了两个或以上的RequestMappingInfo映射,需要比对一下
// 如果上一步查找出了多个Match,则需要选择一个最优Match
// 代码实现就是对Match集进行排序,内部会将两个RequestMappingInfo与当前请求匹配,匹配度较高者排在前面
if (!matches.isEmpty()) {
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
bestMatch = matches.get(0);
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
Match secondBestMatch = matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
String uri = request.getRequestURI();
throw new IllegalStateException(
"Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
}
}
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
} else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
查找HandlerMethod - 匹配RequestMappingInfo映射
private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
// 这里的T是RequestMappingInfo
// 遍历RequestMappingInfo集
for (T mapping : mappings) {
// 与当前请求匹配
T match = getMatchingMapping(mapping, request);
if (match != null) {
// 使用RequestMappingInfo、HandlerMethod封装Match对象
matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
}
}
}
// RequestMappingInfoHandlerMapping.getMatchingMapping方法
protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) {
// 把当前请求与RequestMappingInfo的一系列Condition匹配
return info.getMatchingCondition(request);
}
看一下info.getMatchingCondition方法:
public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
// 匹配请求Method
// methodsCondition封装着该RequestMappingInfo支持的Method集
// 返回null表示不支持当前请求
RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
if (methods == null) {
return null;
}
// 匹配RequestMapping注解的params值
ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
if (params == null) {
return null;
}
// 匹配RequestMapping注解的headers值
HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);
if (headers == null) {
return null;
}
// 匹配Content-Type
ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);
if (consumes == null) {
return null;
}
// 匹配Accept
ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);
if (produces == null) {
return null;
}
// 匹配path
// 内部封装着RequestMapping注解的path值
// 使用AntPathMatcher去尝试匹配请求与path配置
PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request);
if (patterns == null) {
return null;
}
// 匹配自定义Condition
RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);
if (custom == null) {
return null;
}
// 匹配成功时返回
return new RequestMappingInfo(this.name, patterns,
methods, params, headers, consumes, produces, custom.getCondition());
}
查找支持的Adapter
入口
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
getHandlerAdapter方法:
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler");
}
前文介绍,handlerAdapters封装着所有的HandlerAdapter:
其中RequestMappingHandlerAdapter用于处理被@RequestMapping标注的HandlerMethod,《扫描Controller创建HandlerMapping流程》已做过分析,此处介绍一下他的supports方法实现。
其余的几个HandlerAdapter实现类后续会有专门章节介绍。
RequestMappingHandlerAdapter的supports方法
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
执行拦截器preHandle方法
// 执行拦截器preHandle方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
HandlerExecutionChain.applyPreHandle方法:
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
调用执行器处理请求
入口
ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
上文已经介绍,此处ha是RequestMappingHandlerAdapter类型对象。
handle方法:
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
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;
}
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);
// 参数解析器
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
// 返回值解析器
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
// 参数校验相关配置
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
// model and view相关配置
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();
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
// 调用处理器handle
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
// 封装ModelAndView
return getModelAndView(mavContainer, modelFactory, webRequest);
} finally {
webRequest.requestCompleted();
}
}
ServletInvocableHandlerMethod.invokeAndHandle
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);
try {
// 处理接口返回值
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
} catch (Exception ex) {
throw ex;
}
}
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 解析参数
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
// 调用目标方法
return doInvoke(args);
}
protected Object[] getMethodArgumentValues(NativeWebRequest request, 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); // null
if (args[i] != null) {
continue;
}
// 解析参数
try {
args[i] = this.resolvers
.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
} catch (Exception ex) {
throw ex;
}
}
return args;
}
解析参数
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
resolvers是HandlerMethodArgumentResolverComposite对象,里面封装着系统配置的所有的参数解析器:
resolveArgument方法内部首先查找能够处理当前参数的解析器,之后调用解析器resolveArgument方法解析参数,以RequestResponseBodyMethodProcessor实现类为例:
- Resolves method arguments annotated with @RequestBody and handles return values from methods annotated with @ResponseBody by reading and writing to the body of the request or response with an HttpMessageConverter.
- An @RequestBody method argument is also validated if it is annotated with @javax.validation.Valid. In case of validation failure, MethodArgumentNotValidException is raised and results in an HTTP 400 response status code if DefaultHandlerExceptionResolver is configured.
supportsParameter方法:
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(RequestBody.class);
}
resolveArgument方法:
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
parameter = parameter.nestedIfOptional();
// 使用MessageConverter读取
// 从当前封装的MessageConverter集查找支持当前参数的Converter对象,使用canRead方法判断
// 使用Converter对象read方法解析参数
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包装
return adaptArgumentIfNecessary(arg, parameter);
}
解析参数 - MessageConverter
MessageConverter接口:
public interface HttpMessageConverter<T> {
boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);
boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);
List<MediaType> getSupportedMediaTypes();
T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException;
void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException;
}
上文使用的RequestResponseBodyMethodProcessor封装了系统支持的MessageConverter集:
其中MappingJackson2HttpMessageConverter使用Jackson ObjectMapper读写json请求和响应:
- By default, this converter supports application/json and application/*+json with UTF-8 character set. This can be overridden by setting the supportedMediaTypes property.
- The default constructor uses the default configuration provided by Jackson2ObjectMapperBuilder.
- Compatible with Jackson 2.9 and higher, as of Spring 5.0.
其余的MessageConverter实现后续会介绍。
调用目标方法
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
// 调用目标方法
// If the bean method is a bridge method,
// this method returns the bridged (user-defined) method.
// Otherwise it returns the same method as getMethod().
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);
}
}
}
处理接口返回值
// 处理接口返回值
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
returnValueHandlers是HandlerMethodReturnValueHandlerComposite对象,里面封装着系统配置的所有的返回值解析器:
handleReturnValue方法内部首先查找能够匹配当前返回值的处理器,之后调用处理器handleReturnValue方法处理参数,以RequestResponseBodyMethodProcessor实现类为例,这个类既实现了HandlerMethodArgumentResolver,也实现了HandlerMethodReturnValueHandler,所以他既能解析被@RequestBody标注的参数,也能处理被@ResponseBody标注的返回值。
supportsReturnType方法:
public boolean supportsReturnType(MethodParameter returnType) {
return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
returnType.hasMethodAnnotation(ResponseBody.class));
}
handleReturnValue方法:
public void handleReturnValue(@Nullable 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.
// 使用MessageConverter进行序列化之类的操作然后写出到数据流
// 从当前封装的MessageConverter集查找支持当前返回值的Converter对象,使用canWrite方法判断
// 使用Converter对象write方法序列化、写输出流
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
封装ModelAndView
在目标方法处理完毕,就要封装ModelAndView并返回,在RequestMappingHandlerAdapter的invokeHandlerMethod方法中:
return getModelAndView(mavContainer, modelFactory, webRequest);
getModelAndView方法:
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
modelFactory.updateModel(webRequest, mavContainer);
if (mavContainer.isRequestHandled()) {
return null;
}
ModelMap model = mavContainer.getModel();
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
if (model instanceof RedirectAttributes) {
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
if (request != null) {
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
}
return mav;
}
这里再介绍一下ModelAndViewMethodReturnValueHandler处理器,他用来处理ModelAndView类型返回值。
handleReturnValue方法:
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
if (returnValue == null) {
mavContainer.setRequestHandled(true);
return;
}
ModelAndView mav = (ModelAndView) returnValue;
if (mav.isReference()) {
String viewName = mav.getViewName();
mavContainer.setViewName(viewName);
if (viewName != null && isRedirectViewName(viewName)) {
mavContainer.setRedirectModelScenario(true);
}
} else {
View view = mav.getView();
mavContainer.setView(view);
if (view instanceof SmartView && ((SmartView) view).isRedirectView()) {
mavContainer.setRedirectModelScenario(true);
}
}
mavContainer.setStatus(mav.getStatus());
mavContainer.addAllAttributes(mav.getModel());
}
执行拦截器postHandle方法
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
处理ModelAndView返回值
// 处理接口返回值
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
processDispatchResult方法:
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
} else {
// 处理异常
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// 使用ModelAndView渲染页面
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
} else {
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
// 执行拦截器afterCompletion方法
if (mappedHandler != null) {
// Exception (if any) is already handled..
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
处理异常
如果有异常,则处理异常。
processHandlerException方法:
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
@Nullable Object handler, Exception ex) throws Exception {
// Success and error responses may use different content types
request.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
// Check registered HandlerExceptionResolvers...
ModelAndView exMv = null;
// 使用HandlerExceptionResolver集处理异常
if (this.handlerExceptionResolvers != null) {
for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
exMv = resolver.resolveException(request, response, handler, ex);
if (exMv != null) {
break;
}
}
}
// ModelAndView处理
if (exMv != null) {
if (exMv.isEmpty()) {
request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
return null;
}
// We might still need view name translation for a plain error model...
if (!exMv.hasView()) {
String defaultViewName = getDefaultViewName(request);
if (defaultViewName != null) {
exMv.setViewName(defaultViewName);
}
}
WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
return exMv;
}
throw ex;
}
HandlerExceptionResolver集:
- DefaultErrorAttributes - Spring Boot提供,暂不分析
- HandlerExceptionResolverComposite - Spring MVC的异常处理器,他是在WebMvcConfigurationSupport中注入到Spring容器的,会扫描被@ControllerAdvice标注的Bean,封装ControllerAdviceBean和ExceptionHandlerMethodResolver
ExceptionHandlerExceptionResolver类封装着Controller的异常处理通知集:
- exceptionHandlerCache - 保存Controller类里面被@ExceptionHandler注解标注的异常处理方法
- exceptionHandlerAdviceCache - 保存被@ControllerAdvice标注的异常处理方法
在此处,会遍历HandlerExceptionResolver集,调用resolveException方法处理异常,我们重点看一下ExceptionHandlerExceptionResolver的实现方式:
- 从当前Controller类中查找能够处理该异常的ExceptionHandler方法,如果找到,就使用他来处理
- 如果上一步没找到,则在ControllerAdvice异常处理方法中查找,如果找到,就使用他来处理
- 如果上一步没找到,会返回null,之后会进入下一轮迭代,尝试使用ResponseStatusExceptionResolver和DefaultHandlerExceptionResolver处理
渲染ModelAndView
protected void render(
ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
Locale locale =
(this.localeResolver != null ?
this.localeResolver.resolveLocale(request) : request.getLocale());
response.setLocale(locale);
View view;
String viewName = mv.getViewName();
if (viewName != null) {
// We need to resolve the view name.
// 使用视图解析器查找视图
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view");
}
} else {
// No need to lookup: the ModelAndView object contains the actual View object.
view = mv.getView();
if (view == null) {
throw new ServletException("xxx");
}
}
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
// 渲染视图
view.render(mv.getModelInternal(), request, response);
} catch (Exception ex) {
throw ex;
}
}
执行拦截器afterCompletion方法
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
} catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}