说到 Java 开发,现在最流行的框架是什么呢?90% 以上的程序员应该会说是 Spring,而作为 Spring Web 开发的利器 Spring MVC,更是各位 Java Web 开发者的心头好。所以为了能更好、更简单地开发一个 Web 项目,了解下 Spring MVC 的底层逻辑是很有必要的,这将帮助我们了解 Spring MVC 提供的各种扩展点,用更加优雅的方式来实现我们的项目。
整体逻辑
Spring MVC 的整体处理过程如上图所示,调用链还是比较清晰。
- 当请求过来之后,DispatcherServlet 通过 HandlerMapping 获取一个合适的 Handler 来处理请求,这里将获得 HandlerMethod 对象(Controller + Method 封装),并生成 HandlerExecutionChain 对象
- 依据 HandlerMethod ,遍历 DispatcherServlet 中注入的 HandlerAdapter,获的合适的 HandlerAdapter 对象
- 调用 HandlerAdapter 对象的 handler() 方法进行实际的业务处理,HandlerAdapter 对象中,主要依靠 ServletInvocableHandlerMethod 对象来处理参数的解析、业务调用、返回值的处理等
- HandlerAdapter 处理完之后,将返回 ModelAndView 对象
- 如果过程中发生异常将调用 HandlerExceptionResolver 处理异常
- 使用合适的 ViewResolver 解析 View,并使用 View 进行结果渲染
辅助类及入口
下面我们一起通过源码来看下上面的过程,源码版本基于"spring-webmvc-5.2.8.RELEASE"。
辅助类
下面是我读源码过程中用到的相关类。
kotlin
/**
* Spring MVC 生命周期示例
* @author 鱼蛮 on 2019/2/15
**/
@Slf4j
@RestController
public class SpringMvcLifeCycleTestController {
/**
* 用于演示 Spring Mvc 的生命周期
*
* @param date PropertyEditorSupport 处理结果
* @param mvcRequest HandlerMethodArgumentResolver 处理结果
* @return {@link java.lang.String}
*/
@GetMapping(value = "/mvc")
public MvcResponse mvc(@RequestParam("date")Date date, MvcRequest mvcRequest) {
System.out.println("4.call controller,date:" + date + ",params:" + mvcRequest);
return new MvcResponse("成功");
}
@Data
public static class MvcRequest {
private Long id;
private String name;
}
@Data
public static class MvcResponse {
private String data;
public MvcResponse(String data) {
this.data = data;
}
}
}
less
/**
* HandlerInterceptorAdapter 使用示例
*
* @author 鱼蛮 on 2019/2/15
**/
public class HandlerInterceptorAdapterTest extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(@Nonnull HttpServletRequest request, @Nonnull HttpServletResponse response, @Nonnull Object handler) {
System.out.println("1.HandlerInterceptor preHandle");
return true;
}
@Override
public void postHandle(@Nonnull HttpServletRequest request, @Nonnull HttpServletResponse response, @Nonnull Object handler,
@Nullable ModelAndView modelAndView) {
System.out.println("6.HandlerInterceptor postHandle");
}
@Override
public void afterCompletion(@Nonnull HttpServletRequest request, @Nonnull HttpServletResponse response, @Nonnull Object handler,
@Nullable Exception ex) {
System.out.println("7.HandlerInterceptor afterCompletion");
}
}
arduino
/**
* PropertyEditorSupport 使用示例
*
* @author 鱼蛮 on 2019/2/15
**/
@ControllerAdvice
public class EditorTest {
/**
* 注册 {@link Date} 类型解析.
*
* @param binder 数据绑定器
* @param request request
*/
@InitBinder
public void registerCustomEditors(WebDataBinder binder, WebRequest request) {
binder.registerCustomEditor(Date.class, new DateEditor());
// 统一去除String参数中的前后空格
StringTrimmerEditor stringTrimmer = new StringTrimmerEditor(true);
binder.registerCustomEditor(String.class, stringTrimmer);
}
/**
* 日期字段自动转 java.util.Date
**/
@Slf4j
public class DateEditor extends PropertyEditorSupport {
/** 常规日期时间格式 */
public static final String DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
/** 精简日期时间格式 */
public static final String SIMPLE_DATETIME_PATTERN = "yyyyMMddHHmmss";
/** 常规日期格式 */
public static final String DATE_PATTERN = "yyyy-MM-dd";
/** 精简日期格式 */
public static final String SIMPLE_DATE_PATTERN = "yyyyMMdd";
@Override
public void setAsText(String text) throws IllegalArgumentException {
if (StringUtils.isBlank(text)) {
setValue(null);
return;
}
Date date = null;
try {
date = DateUtils.parseDate(text, DATETIME_PATTERN, SIMPLE_DATETIME_PATTERN, DATE_PATTERN, SIMPLE_DATE_PATTERN);
} catch (ParseException e) {
log.warn(String.format("fail to parse java.util.Date type with value: %s", text), e);
}
System.out.println("2.PropertyEditor");
setValue(date);
}
}
}
less
/**
* HandlerMethodArgumentResolver 使用示例
*
* @author 鱼蛮 on 2019/2/15
**/
public class HandlerMethodArgumentResolverTest implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(@Nonnull MethodParameter methodParameter) {
return MvcRequest.class == methodParameter.getParameterType();
}
@Override
public Object resolveArgument(@Nonnull MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer,
@Nonnull NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) {
String id = nativeWebRequest.getParameter("mvcParams.id");
String name = nativeWebRequest.getParameter("mvcParams.name");
MvcRequest mvcRequest = new MvcRequest();
mvcRequest.setId(Optional.ofNullable(id).map(Long::parseLong).orElse(null));
mvcRequest.setName(name);
System.out.println("3.HandlerMethodArgumentResolver");
return mvcRequest;
}
}
less
/**
* ResponseBodyAdvice 使用示例
*
* @author 鱼蛮 on 2019/2/15
**/
@ControllerAdvice
public class ResponseBodyAdviceTest implements ResponseBodyAdvice<MvcResponse> {
@Override
public boolean supports(@Nonnull MethodParameter returnType, @Nonnull Class converterType) {
return returnType.getParameterType() == MvcResponse.class;
}
@Override
public MvcResponse beforeBodyWrite(MvcResponse body, @Nonnull MethodParameter returnType,
@Nonnull MediaType selectedContentType,
@Nonnull Class<? extends HttpMessageConverter<?>> selectedConverterType,
@Nonnull ServerHttpRequest request, @Nonnull ServerHttpResponse response) {
System.out.println("5.ResponseBodyAdvice");
return new MvcResponse(Optional.ofNullable(body).map(e -> e.getData() + "_advice").orElse(null));
}
}
DispatchServlet#doDispatch()
源码的入口也很好找,因为 Spring MVC 是基于 Servlet 规范的,所以 DispartchServlet 继承自 HttpServlet,通过的 HttpServelt 的入口很容易找到最终的调用入口是 DispatchServlet#doDispatch() 。这个方法就是整个 Spring MVC 的核心处理过程。
ini
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 {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 获取处理请求的 HandlerExecutionChain 对象
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 获得处理请求的 HandlerAdapter 对象
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
... ...
// 调用 HandlerInterceptor 的 preHandler() 方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 实际的请求处理
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
... ...
// 调用 HandlerInterceptor 的 postHandler() 方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
... ...
}
// 执行 ModelAndView 的解析、渲染
// 调用 HandlerInterceptor 的 afterCompletion() 方法
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
... ...
}
过程解读
DispatchServlet#getHandler()
首先是调用 DispatchServlet#getHandler() 方法来获得 HandlerExecutionChain 对象。这个其实主要就是通过遍历已经注入的类型为 List 的 handlerMappings 属性,来找一个合适的 HandlerMapping,再通过 HandlerMapping 来处理,对普通的请求基本都适用 RequestMappingInfoHandlerMapping。
RequestMappingInfoHandlerMapping#getHandler()
getHandlerInternal()
RequestMappingInfoHandlerMapping 中将首先调用 getHandlerInternal() 方法,通过请求中的 URL 地址,获得相应的 HandlerMethod 对象,而 HandlerMethod 里面包装的就是实际的业务逻辑处理类 Controller 及 Method 等信息。
java
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
request.setAttribute(LOOKUP_PATH, lookupPath);
this.mappingRegistry.acquireReadLock();
try {
// 根据请求的 URL 去找最合适的 HandlerMethod
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
getHandlerExecutionChain()
这一步将获得一个 HandlerExecutionChain 对象,会将上一步中获得的 HandlerMethod 对象作为属性注入其中。并且根据请求 URL 匹配 HandlerInterceptor(拦截器),组装到 HandlerExecutionChain 对象中,后面都是使用 HandlerExecutionChain 来间接触发 HandlerInterceptor。
java
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
// 根据请求的 URL 获取匹配的 HandlerInterceptor,加入到 chain 中
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
DispatchServlet#getHandlerAdapter()
这一步其实很简单,就是通过上面获取的 HandlerExecutionChain 对象中的 handler 属性(HandlerMethod 对象)来获取支持的 HandlerAdapter 对象。
这里最终获得的 HandlerAdapter 对象是:RequestMappingHandlerAdapter。
kotlin
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
}
HandlerExecutionChain#applyPreHandle()
在调用实际业务处理代码之前,会先执行 HandlerExecutionChain#applyPreHandle() 方法,而这个就会调用上面匹配的拦截器 HandlerInterceptor 中的 preHandle() 方法。如果返回值不为 true,将结束请求的处理。
RequestMappingHandlerAdapter#handle()
获得了 RequestMappingHandlerAdapter 对象之后,就需要调 RequestMappingHandlerAdapter#handle() 方法进行实际的业务调用,及相关处理。这个方法只是一个对外接口方法,里面将调用真正的实现方法 handleInternal(),继续往下,将调用核心的逻辑处理方法 invokeHandlerMethod()。
invokeHandlerMethod()
kotlin
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
... ...
// 初始化 ServletInvocableHandlerMethod 对象
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
// 核心属性设置 HandlerMethodArgumentResolver
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
// 核心属性设置 HandlerMethodReturnValueHandler
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
// 核心属性用于参数解析,PropertyEditorSupport
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
... ...
// 执行业务逻辑方法,并且处理结果
invocableMethod.invokeAndHandle(webRequest, mavContainer);
... ...
return getModelAndView(mavContainer, modelFactory, webRequest);
}
... ...
}
在 invokeHandlerMethod() 方法中,首先会调用 createInvocableHandlerMethod() 方法,创建 ServletInvocableHandlerMethod 对象。
ini
protected HandlerMethod(HandlerMethod handlerMethod) {
Assert.notNull(handlerMethod, "HandlerMethod is required");
this.bean = handlerMethod.bean;
this.beanFactory = handlerMethod.beanFactory;
this.beanType = handlerMethod.beanType;
this.method = handlerMethod.method;
this.bridgedMethod = handlerMethod.bridgedMethod;
this.parameters = handlerMethod.parameters;
this.responseStatus = handlerMethod.responseStatus;
this.responseStatusReason = handlerMethod.responseStatusReason;
this.description = handlerMethod.description;
this.resolvedFromHandlerMethod = handlerMethod.resolvedFromHandlerMethod;
}
一路追踪下去,会发现 ServletInvocableHandlerMethod 继承自 HandlerMethod,创建的时候会将上面获得的 HandlerMethod 对象传入,读取核心属性来创建 ServletInvocableHandlerMethod 对象。
接着会调用 ServletInvocableHandlerMethod#setHandlerMethodArgumentResolvers(),ServletInvocableHandlerMethod#setHandlerMethodReturnValueHandlers() 等方法,这些方法都是用来设置核心的扩展属性,用于解析请求参数(HandlerMethodArgumentResolver),返回值处理(HandlerMethodReturnValueHandler)等,我们前面的辅助类中有相应的实现类。
ServletInvocableHandlerMethod#invokeAndHandle()
ServletInvocableHandlerMethod 对象初始化完成之后,就会执行其 invokeAndHandle() 方法,来调用真正的业务处理代码,并处理返回结果。
java
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 执行业务调用
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
... ...
try {
// 返回值处理
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
... ...
}
invokeForRequest()
less
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
... ...
return doInvoke(args);
}
在 invokeForRequest() 方法中将先调用 getMethodArgumentValues() 方法,来根据请求及扩展点(HandlerMethodArgumentResolver、PropertyEditorSupport)来解析方法的输入参数。
ini
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable 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] = findProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
// 判断是否可以解析,并且代用 Resolver 去解析
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
}
... ...
}
return args;
}
getMethodArgumentValues() 中将判断输入的参数是否可以解析,然后调用 HandlerMethodArgumentResolverComposite#resolveArgument() 方法来解析参数。
HandlerMethodArgumentResolverComposite 是一个组合类,里面包含了系统中所有注册过的 HandlerMethodArgumentResolver 对象,当然也包含我们自定义的 HandlerMethodArgumentResolverTest。
调用方法的时候还会将 WebDataBinderFactory 作为参数传入,在 RequestParamMethodArgumentResolver 中,将使用 WebDataBinderFactory 做相应类型的参数解析。
如果是 @RequestBody 注解的参数将调用 RequestResponseBodyMethodProcessor 进行处理,RequestResponseBodyMethodProcessor 类同时实现了 HandlerMethodArgumentResolver,HandlerMethodReturnValueHandler,可以同时对 "Body" 类型的请求参数、返回结果进行处理。RequestResponseBodyMethodProcessor 处理请求参数的时候,将调用 RequestBodyAdvice 扩展点,支持对输入 @RequestBody 的前置、后置、空值处理。
在获得了最终的方法执行参数后,就可以调用实际的业务逻辑处理方法了,即 doInvoke()。
scss
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
return getBridgedMethod().invoke(getBean(), args);
}
... ...
}
doInvoke() 方法很简单,就是通过反射调用了实际的业务逻辑处理方法,获得返回值之后就可以返回了。
HandlerMethodReturnValueHandlerComposite#handleReturnValue() 下面就是处理返回值的操作了,HandlerMethodReturnValueHandlerComposite 看名字也知道这也是一个组合类,提供了一个统一的对外接口。里面会根据返回类型,获取合适的 HandlerMethodReturnValueHandler 进行处理。
less
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
}
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
因为我们使用的是 @ResponseBody 注解,所以将选择 RequestResponseBodyMethodProcessor 进行处理。在 RequestResponseBodyMethodProcessor 的 handleReturnValue() 方法中,将执行 ModelAndViewContainer#setRequestHandled(true); 标记 Request 已经被处理过了。继续往下将执行 RequestResponseBodyMethodProcessor#writeWithMessageConverters() 方法。
ini
protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType,
ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
Object body;
Class<?> valueType;
Type targetType;
if (value instanceof CharSequence) {
... ...
}
else {
// 获得返回类型
body = value;
valueType = getReturnValueType(body, returnType);
targetType = GenericTypeResolver.resolveType(getGenericType(returnType), returnType.getContainingClass());
}
... ...
MediaType selectedMediaType = null;
MediaType contentType = outputMessage.getHeaders().getContentType();
boolean isContentTypePreset = contentType != null && contentType.isConcrete();
if (isContentTypePreset) {
... ...
}
else {
// 判断支持的 MediaType,会综合 @RequestMapping 中的 consumes,produces 属性判断
HttpServletRequest request = inputMessage.getServletRequest();
List<MediaType> acceptableTypes = getAcceptableMediaTypes(request);
List<MediaType> producibleTypes = getProducibleMediaTypes(request, valueType, targetType);
... ...
List<MediaType> mediaTypesToUse = new ArrayList<>();
for (MediaType requestedType : acceptableTypes) {
for (MediaType producibleType : producibleTypes) {
if (requestedType.isCompatibleWith(producibleType)) {
mediaTypesToUse.add(getMostSpecificMediaType(requestedType, producibleType));
}
}
}
... ...
// 选取一个最合适的 MediaType
MediaType.sortBySpecificityAndQuality(mediaTypesToUse);
for (MediaType mediaType : mediaTypesToUse) {
if (mediaType.isConcrete()) {
selectedMediaType = mediaType;
break;
}
... ...
}
... ...
}
if (selectedMediaType != null) {
selectedMediaType = selectedMediaType.removeQualityValue();
// 遍历 HttpMessageConverter
for (HttpMessageConverter<?> converter : this.messageConverters) {
GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ?
(GenericHttpMessageConverter<?>) converter : null);
// 看是否支持当前的返回类型,及 MediaType
if (genericConverter != null ?
((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :
converter.canWrite(valueType, selectedMediaType)) {
// 调用 ResponseBodyAdvice 处理返回信息
body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,
(Class<? extends HttpMessageConverter<?>>) converter.getClass(),
inputMessage, outputMessage);
if (body != null) {
Object theBody = body;
LogFormatUtils.traceDebug(logger, traceOn ->
"Writing [" + LogFormatUtils.formatValue(theBody, !traceOn) + "]");
addContentDispositionHeader(inputMessage, outputMessage);
// 调用 Converter 输出返回信息
if (genericConverter != null) {
genericConverter.write(body, targetType, selectedMediaType, outputMessage);
}
else {
((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);
}
}
else {
... ...
}
return;
}
}
}
... ...
}
这段代码比较长,首先会根据返回值及返回类型定义,获取返回值的实际类型。然后会根据 @RequestMapping 注解中的 consumes,produces 属性,综合判断可以支持的 MediaType(Content-Type),并选择一个最合适的 MediaType。
之后会遍历当前 Processor 中注入的 HttpMessageConverter 对象,来选择支持的 HttpMessageConverter 对象。如果没有额外指定这里将选择 MappingJackson2HttpMessageConverter,当然也可以根据需要指定 FastJsonHttpMessageConverter 等 HttpMessageConverter。
在数据写出之前,将使用 ResponseBodyAdvice 做输出前的最终处理。
调用完 ResponseBodyAdvice#beforeBodyWrite() 之后,就会调用 HttpMessageConverter#write() 方法进行数据写出。
less
public final void write(final T t, @Nullable final Type type, @Nullable MediaType contentType,
HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
// 初始化 Header 信息
final HttpHeaders headers = outputMessage.getHeaders();
addDefaultHeaders(headers, t, contentType);
if (outputMessage instanceof StreamingHttpOutputMessage) {
... ...
}
else {
// 写数据
writeInternal(t, type, outputMessage);
outputMessage.getBody().flush();
}
}
在 MappingJackson2HttpMessageConverter#write() 方法中,将首先初始化 HttpHeaders 信息,然后调用 writeInternal() 方法,进行数据写出。writeInternal() 方法就是 MappingJackson2HttpMessageConverter 实现的实际数据输出方法,这里将会把数据序列号,并通过 OutputStream 输出数据。
getModelAndView()
一路 return 之后,将执行到 getModelAndView() 方法。
scss
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());
}
... ...
return mav;
}
由于 Request 在前面已经处理完了,所以,这里将返回 null。否则会根据 ModelAndViewContainer,组装 ModelAndView 对象。
HandlerExecutionChain#applyPostHandle()
又是一路 return,将回到 DispatchServlet#doDispatch() 方法中,接着往下执行 HandlerExecutionChain#applyPostHandle() 方法,而这个就会调用注册的拦截器 HandlerInterceptor 的 postHandle() 方法。
DispatchServlet#processDispatchResult()
最终将调用 DispatchServlet#processDispatchResult() 方法,这个是整个处理过程的收尾方法了。
less
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false;
// 如果发生异常,将调用 HandlerExceptionResolver 处理
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// 如果 ModelAndView 不为空,将执行 ModelAndView 的渲染
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
... ...
}
... ...
// 调用 HandlerInterceptor 的 afterCompletion() 方法
if (mappedHandler != null) {
// Exception (if any) is already handled..
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
在 DispatchServlet#processDispatchResult() 方法中,将首先判断处理过程中是否发生异常,如果是,将调用注册的 HandlerExceptionResolver#resolveException() 方法来处理异常。
之后如果 ModelAndView 不为空,将调用 render() 方法来执行视图的渲染。在 render() 方法中首先根据注册的 ViewResolver 来解析获得 View 对象,然后调用 View#render() 方法进行最终的渲染。
如果 ModelAndView 为空,比如我们采用 @ResponseBody 注解,在之前已经处理过返回结果,那么这里就不会再做视图的渲染工作。
无论 ModelAndView 是否为空,最后都会调用 HandlerExecutionChain#triggerAfterCompletion() 方法,也就是会调用 HandlerInterceptor#afterCompletion() ,执行请求最后的拦截器扩展点。