
說到 Java 開發(fā),現(xiàn)在最流行的框架是什么呢?90% 以上的程序員應(yīng)該會(huì)說是 Spring,而作為 Spring Web 開發(fā)的利器 Spring MVC,更是各位 Java Web 開發(fā)者的心頭好。所以為了能更好、更簡單地開發(fā)一個(gè) Web 項(xiàng)目,了解下 Spring MVC 的底層邏輯是很有必要的,這將幫助我們了解 Spring MVC 提供的各種擴(kuò)展點(diǎn),用更加優(yōu)雅的方式來實(shí)現(xiàn)我們的項(xiàng)目。
整體邏輯

Spring MVC 的整體處理過程如上圖所示,調(diào)用鏈還是比較清晰。
- 當(dāng)請求過來之后,DispatcherServlet 通過 HandlerMapping 獲取一個(gè)合適的 Handler 來處理請求,這里將獲得 HandlerMethod 對象(Controller + Method 封裝),并生成 HandlerExecutionChain 對象
- 依據(jù) HandlerMethod ,遍歷 DispatcherServlet 中注入的 HandlerAdapter,獲的合適的 HandlerAdapter 對象
- 調(diào)用 HandlerAdapter 對象的 handler() 方法進(jìn)行實(shí)際的業(yè)務(wù)處理,HandlerAdapter 對象中,主要依靠 ServletInvocableHandlerMethod 對象來處理參數(shù)的解析、業(yè)務(wù)調(diào)用、返回值的處理等
- HandlerAdapter 處理完之后,將返回 ModelAndView 對象
- 如果過程中發(fā)生異常將調(diào)用 HandlerExceptionResolver 處理異常
- 使用合適的 ViewResolver 解析 View,并使用 View 進(jìn)行結(jié)果渲染
輔助類及入口
下面我們一起通過源碼來看下上面的過程,源碼版本基于“spring-webmvc-5.2.8.RELEASE”。
輔助類
下面是我讀源碼過程中用到的相關(guān)類。
/**
* Spring MVC 生命周期示例
* @author 魚蠻 on 2019/2/15
**/
@Slf4j
@RestController
public class SpringMvcLifeCycleTestController {
/**
* 用于演示 Spring Mvc 的生命周期
*
* @param date PropertyEditorSupport 處理結(jié)果
* @param mvcRequest HandlerMethodArgumentResolver 處理結(jié)果
* @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;
}
}
}
/**
* 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");
}
}
/**
* PropertyEditorSupport 使用示例
*
* @author 魚蠻 on 2019/2/15
**/
@ControllerAdvice
public class EditorTest {
/**
* 注冊 {@link Date} 類型解析.
*
* @param binder 數(shù)據(jù)綁定器
* @param request request
*/
@InitBinder
public void registerCustomEditors(WebDataBinder binder, WebRequest request) {
binder.registerCustomEditor(Date.class, new DateEditor());
// 統(tǒng)一去除String參數(shù)中的前后空格
StringTrimmerEditor stringTrimmer = new StringTrimmerEditor(true);
binder.registerCustomEditor(String.class, stringTrimmer);
}
/**
* 日期字段自動(dòng)轉(zhuǎn) java.util.Date
**/
@Slf4j
public class DateEditor extends PropertyEditorSupport {
/** 常規(guī)日期時(shí)間格式 */
public static final String DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
/** 精簡日期時(shí)間格式 */
public static final String SIMPLE_DATETIME_PATTERN = "yyyyMMddHHmmss";
/** 常規(guī)日期格式 */
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);
}
}
}
/**
* 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;
}
}
/**
* 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()
源碼的入口也很好找,因?yàn)?Spring MVC 是基于 Servlet 規(guī)范的,所以 DispartchServlet 繼承自 HttpServlet,通過的 HttpServelt 的入口很容易找到最終的調(diào)用入口是 DispatchServlet#doDispatch() 。這個(gè)方法就是整個(gè) Spring MVC 的核心處理過程。
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());
... ...
// 調(diào)用 HandlerInterceptor 的 preHandler() 方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 實(shí)際的請求處理
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
... ...
// 調(diào)用 HandlerInterceptor 的 postHandler() 方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
... ...
}
// 執(zhí)行 ModelAndView 的解析、渲染
// 調(diào)用 HandlerInterceptor 的 afterCompletion() 方法
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
... ...
}
過程解讀
DispatchServlet#getHandler()
首先是調(diào)用 DispatchServlet#getHandler() 方法來獲得 HandlerExecutionChain 對象。這個(gè)其實(shí)主要就是通過遍歷已經(jīng)注入的類型為 List<HandlerMapping> 的 handlerMappings 屬性,來找一個(gè)合適的 HandlerMapping,再通過 HandlerMapping 來處理,對普通的請求基本都適用 RequestMappingInfoHandlerMapping。
RequestMappingInfoHandlerMapping#getHandler()
getHandlerInternal()
RequestMappingInfoHandlerMapping 中將首先調(diào)用 getHandlerInternal() 方法,通過請求中的 URL 地址,獲得相應(yīng)的 HandlerMethod 對象,而 HandlerMethod 里面包裝的就是實(shí)際的業(yè)務(wù)邏輯處理類 Controller 及 Method 等信息。
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
request.setAttribute(LOOKUP_PATH, lookupPath);
this.mappingRegistry.acquireReadLock();
try {
// 根據(jù)請求的 URL 去找最合適的 HandlerMethod
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
getHandlerExecutionChain()
這一步將獲得一個(gè) HandlerExecutionChain 對象,會(huì)將上一步中獲得的 HandlerMethod 對象作為屬性注入其中。并且根據(jù)請求 URL 匹配 HandlerInterceptor(攔截器),組裝到 HandlerExecutionChain 對象中,后面都是使用 HandlerExecutionChain 來間接觸發(fā) HandlerInterceptor。
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;
// 根據(jù)請求的 URL 獲取匹配的 HandlerInterceptor,加入到 chain 中
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
DispatchServlet#getHandlerAdapter()
這一步其實(shí)很簡單,就是通過上面獲取的 HandlerExecutionChain 對象中的 handler 屬性(HandlerMethod 對象)來獲取支持的 HandlerAdapter 對象。
這里最終獲得的 HandlerAdapter 對象是:RequestMappingHandlerAdapter。
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
}
HandlerExecutionChain#applyPreHandle()
在調(diào)用實(shí)際業(yè)務(wù)處理代碼之前,會(huì)先執(zhí)行 HandlerExecutionChain#applyPreHandle() 方法,而這個(gè)就會(huì)調(diào)用上面匹配的攔截器 HandlerInterceptor 中的 preHandle() 方法。如果返回值不為 true,將結(jié)束請求的處理。
RequestMappingHandlerAdapter#handle()
獲得了 RequestMappingHandlerAdapter 對象之后,就需要調(diào) RequestMappingHandlerAdapter#handle() 方法進(jìn)行實(shí)際的業(yè)務(wù)調(diào)用,及相關(guān)處理。這個(gè)方法只是一個(gè)對外接口方法,里面將調(diào)用真正的實(shí)現(xiàn)方法 handleInternal(),繼續(xù)往下,將調(diào)用核心的邏輯處理方法 invokeHandlerMethod()。
invokeHandlerMethod()
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
... ...
// 初始化 ServletInvocableHandlerMethod 對象
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
// 核心屬性設(shè)置 HandlerMethodArgumentResolver
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
// 核心屬性設(shè)置 HandlerMethodReturnValueHandler
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
// 核心屬性用于參數(shù)解析,PropertyEditorSupport
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
... ...
// 執(zhí)行業(yè)務(wù)邏輯方法,并且處理結(jié)果
invocableMethod.invokeAndHandle(webRequest, mavContainer);
... ...
return getModelAndView(mavContainer, modelFactory, webRequest);
}
... ...
}
在 invokeHandlerMethod() 方法中,首先會(huì)調(diào)用 createInvocableHandlerMethod() 方法,創(chuàng)建 ServletInvocableHandlerMethod 對象。
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;
}
一路追蹤下去,會(huì)發(fā)現(xiàn) ServletInvocableHandlerMethod 繼承自 HandlerMethod,創(chuàng)建的時(shí)候會(huì)將上面獲得的 HandlerMethod 對象傳入,讀取核心屬性來創(chuàng)建 ServletInvocableHandlerMethod 對象。
接著會(huì)調(diào)用 ServletInvocableHandlerMethod#setHandlerMethodArgumentResolvers(),ServletInvocableHandlerMethod#setHandlerMethodReturnValueHandlers() 等方法,這些方法都是用來設(shè)置核心的擴(kuò)展屬性,用于解析請求參數(shù)(HandlerMethodArgumentResolver),返回值處理(HandlerMethodReturnValueHandler)等,我們前面的輔助類中有相應(yīng)的實(shí)現(xiàn)類。
ServletInvocableHandlerMethod#invokeAndHandle()
ServletInvocableHandlerMethod 對象初始化完成之后,就會(huì)執(zhí)行其 invokeAndHandle() 方法,來調(diào)用真正的業(yè)務(wù)處理代碼,并處理返回結(jié)果。
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 執(zhí)行業(yè)務(wù)調(diào)用
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
... ...
try {
// 返回值處理
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
... ...
}
invokeForRequest()
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
... ...
return doInvoke(args);
}
在 invokeForRequest() 方法中將先調(diào)用 getMethodArgumentValues() 方法,來根據(jù)請求及擴(kuò)展點(diǎn)(HandlerMethodArgumentResolver、PropertyEditorSupport)來解析方法的輸入?yún)?shù)。
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() 中將判斷輸入的參數(shù)是否可以解析,然后調(diào)用 HandlerMethodArgumentResolverComposite#resolveArgument() 方法來解析參數(shù)。
HandlerMethodArgumentResolverComposite 是一個(gè)組合類,里面包含了系統(tǒng)中所有注冊過的 HandlerMethodArgumentResolver 對象,當(dāng)然也包含我們自定義的 HandlerMethodArgumentResolverTest。
調(diào)用方法的時(shí)候還會(huì)將 WebDataBinderFactory 作為參數(shù)傳入,在 RequestParamMethodArgumentResolver 中,將使用 WebDataBinderFactory 做相應(yīng)類型的參數(shù)解析。
如果是 @RequestBody 注解的參數(shù)將調(diào)用 RequestResponseBodyMethodProcessor 進(jìn)行處理,RequestResponseBodyMethodProcessor 類同時(shí)實(shí)現(xiàn)了 HandlerMethodArgumentResolver,HandlerMethodReturnValueHandler,可以同時(shí)對 “Body” 類型的請求參數(shù)、返回結(jié)果進(jìn)行處理。RequestResponseBodyMethodProcessor 處理請求參數(shù)的時(shí)候,將調(diào)用 RequestBodyAdvice 擴(kuò)展點(diǎn),支持對輸入 @RequestBody 的前置、后置、空值處理。
在獲得了最終的方法執(zhí)行參數(shù)后,就可以調(diào)用實(shí)際的業(yè)務(wù)邏輯處理方法了,即 doInvoke()。
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
return getBridgedMethod().invoke(getBean(), args);
}
... ...
}
doInvoke() 方法很簡單,就是通過反射調(diào)用了實(shí)際的業(yè)務(wù)邏輯處理方法,獲得返回值之后就可以返回了。
HandlerMethodReturnValueHandlerComposite#handleReturnValue()
下面就是處理返回值的操作了,HandlerMethodReturnValueHandlerComposite 看名字也知道這也是一個(gè)組合類,提供了一個(gè)統(tǒng)一的對外接口。里面會(huì)根據(jù)返回類型,獲取合適的 HandlerMethodReturnValueHandler 進(jìn)行處理。
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);
}
因?yàn)槲覀兪褂玫氖?@ResponseBody 注解,所以將選擇 RequestResponseBodyMethodProcessor 進(jìn)行處理。在 RequestResponseBodyMethodProcessor 的 handleReturnValue() 方法中,將執(zhí)行 ModelAndViewContainer#setRequestHandled(true); 標(biāo)記 Request 已經(jīng)被處理過了。繼續(xù)往下將執(zhí)行 RequestResponseBodyMethodProcessor#writeWithMessageConverters() 方法。
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,會(huì)綜合 @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));
}
}
}
... ...
// 選取一個(gè)最合適的 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);
// 看是否支持當(dāng)前的返回類型,及 MediaType
if (genericConverter != null ?
((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :
converter.canWrite(valueType, selectedMediaType)) {
// 調(diào)用 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);
// 調(diào)用 Converter 輸出返回信息
if (genericConverter != null) {
genericConverter.write(body, targetType, selectedMediaType, outputMessage);
}
else {
((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);
}
}
else {
... ...
}
return;
}
}
}
... ...
}
這段代碼比較長,首先會(huì)根據(jù)返回值及返回類型定義,獲取返回值的實(shí)際類型。然后會(huì)根據(jù) @RequestMapping 注解中的 consumes,produces 屬性,綜合判斷可以支持的 MediaType(Content-Type),并選擇一個(gè)最合適的 MediaType。
之后會(huì)遍歷當(dāng)前 Processor 中注入的 HttpMessageConverter 對象,來選擇支持的 HttpMessageConverter 對象。如果沒有額外指定這里將選擇 MappingJackson2HttpMessageConverter,當(dāng)然也可以根據(jù)需要指定 FastJsonHttpMessageConverter 等 HttpMessageConverter。
在數(shù)據(jù)寫出之前,將使用 ResponseBodyAdvice 做輸出前的最終處理。
調(diào)用完 ResponseBodyAdvice#beforeBodyWrite() 之后,就會(huì)調(diào)用 HttpMessageConverter#write() 方法進(jìn)行數(shù)據(jù)寫出。
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 {
// 寫數(shù)據(jù)
writeInternal(t, type, outputMessage);
outputMessage.getBody().flush();
}
}
在 MappingJackson2HttpMessageConverter#write() 方法中,將首先初始化 HttpHeaders 信息,然后調(diào)用 writeInternal() 方法,進(jìn)行數(shù)據(jù)寫出。writeInternal() 方法就是 MappingJackson2HttpMessageConverter 實(shí)現(xiàn)的實(shí)際數(shù)據(jù)輸出方法,這里將會(huì)把數(shù)據(jù)序列號(hào),并通過 OutputStream 輸出數(shù)據(jù)。
getModelAndView()
一路 return 之后,將執(zhí)行到 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());
}
... ...
return mav;
}
由于 Request 在前面已經(jīng)處理完了,所以,這里將返回 null。否則會(huì)根據(jù) ModelAndViewContainer,組裝 ModelAndView 對象。
HandlerExecutionChain#applyPostHandle()
又是一路 return,將回到 DispatchServlet#doDispatch() 方法中,接著往下執(zhí)行 HandlerExecutionChain#applyPostHandle() 方法,而這個(gè)就會(huì)調(diào)用注冊的攔截器 HandlerInterceptor 的 postHandle() 方法。
DispatchServlet#processDispatchResult()
最終將調(diào)用 DispatchServlet#processDispatchResult() 方法,這個(gè)是整個(gè)處理過程的收尾方法了。
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false;
// 如果發(fā)生異常,將調(diào)用 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 不為空,將執(zhí)行 ModelAndView 的渲染
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
... ...
}
... ...
// 調(diào)用 HandlerInterceptor 的 afterCompletion() 方法
if (mappedHandler != null) {
// Exception (if any) is already handled..
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
在 DispatchServlet#processDispatchResult() 方法中,將首先判斷處理過程中是否發(fā)生異常,如果是,將調(diào)用注冊的 HandlerExceptionResolver#resolveException() 方法來處理異常。
之后如果 ModelAndView 不為空,將調(diào)用 render() 方法來執(zhí)行視圖的渲染。在 render() 方法中首先根據(jù)注冊的 ViewResolver 來解析獲得 View 對象,然后調(diào)用 View#render() 方法進(jìn)行最終的渲染。
如果 ModelAndView 為空,比如我們采用 @ResponseBody 注解,在之前已經(jīng)處理過返回結(jié)果,那么這里就不會(huì)再做視圖的渲染工作。
無論 ModelAndView 是否為空,最后都會(huì)調(diào)用 HandlerExecutionChain#triggerAfterCompletion() 方法,也就是會(huì)調(diào)用 HandlerInterceptor#afterCompletion() ,執(zhí)行請求最后的攔截器擴(kuò)展點(diǎn)。