handleInternal
使用給定的處理器方法處理請求。
AbstractHandlerMethodAdapter
中定義的 protected 抽象方法,專門由該子類實作。
開始處理請求,傳回一個ModelAndView。
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
checkRequest(request);
// 如果需要,在同步塊中執行invokeHandlerMethod,預設不
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);
}
// 處理Cache-Control請求頭(若你沒有set
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
} else {
prepareResponse(response);
}
}
return mav;
}
剩下的便是本擴充卡最為重要的一個方法:invokeHandlerMethod():
// 它的作用就是執行目标的HandlerMethod,然後傳回一個ModelAndView
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
// 注意:此處隻有try-finally 哦
// 因為invocableMethod.invokeAndHandle(webRequest, mavContainer)是可能會抛出異常的(交給全局異常處理)
try {
// 最終建立的是一個ServletRequestDataBinderFactory,持有所有@InitBinder的method方法們
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
// 建立一個ModelFactory,@ModelAttribute啥的方法就會被引用進來
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
// 把HandlerMethod包裝為ServletInvocableHandlerMethod,具有invoke執行的能力喽
// 下面這幾部便是一直給invocableMethod的各大屬性指派~~~
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);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
// 把上個request裡的值放進來到本request裡
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
// model工廠:把它裡面的Model值放進mavContainer容器内(此處@ModelAttribute/@SessionAttribute啥的生效)
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);
// 它不管是不是異步請求都先用AsyncWebRequest 包裝了一下,但是若是同步請求
// asyncManager.hasConcurrentResult()肯定是為false的~~~
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);
}
// 此處其實就是調用ServletInvocableHandlerMethod#invokeAndHandle()方法喽
// 關于它你可以來這裡:https://fangshixiang.blog.csdn.net/article/details/98385163
// 注意哦:任何HandlerMethod執行完後都是把結果放在了mavContainer裡(它可能有Model,可能有View,可能啥都木有~~)
// 是以最後的getModelAndView()又得一看
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
} finally {
webRequest.requestCompleted();
}
}
任何處理器執行完後,最終傳回的的都是一個ModelAndView對象,這得益于getModelAndView()這個方法的适配處理:
// @Nullable:表示它傳回的可以是個null哦~(若木有視圖,就直接不會render啦~因為response已經寫入過值了)
@Nullable
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
// 把session裡面的内容寫入
modelFactory.updateModel(webRequest, mavContainer);
// Tips:若已經被處理過,那就傳回null喽~~(比如若是@ResponseBody這種,這裡就是true)
if (mavContainer.isRequestHandled()) {
return null;
}
// 通過View、Model、Status構造出一個ModelAndView,最終就可以完成渲染了
ModelMap model = mavContainer.getModel();
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
if (!mavContainer.isViewReference()) { // 是否是String類型
mav.setView((View) mavContainer.getView());
}
// 對重定向RedirectAttributes參數的支援(兩個請求之間傳遞參數,使用的是ATTRIBUTE)
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;
}
執行完HandlerMethod後得到一個ModelAndView,它可能是null(比如已被處理過),那最終交給DispatcherServlet就沒有後續處理了,否則會做視圖渲染:render()。
Spring MVC預設裝配了哪些HandlerAdapter呢?
開啟@EnableWebMvc:
總結
RequestMappingHandlerAdapter作為HandlerAdapter适配模式的實作,由于@RequestMapping成為了使用Spring MVC的幾乎唯一選擇,是以它成為了實際意義上的标準實作