這是一個(gè)最經(jīng)典的SpringMVC
執(zhí)行流程圖爪模,其中最核心的三個(gè)地方是: HandlerMapping
霉猛、HandlerAdapter
、HttpMessageConverter
。
首先,從DispatcherServlet
入手,先看下DispatcherServlet
繼承圖:
從圖可以得知,DispatcherServlet本質(zhì)上就是Servlet,那么Servlet生命周期最主要的的三個(gè)方法時(shí):void init(ServletConfig config),void service(ServletRequest request,ServletResponse response)劳景,void destroy()瓮钥。
看了源代碼之后發(fā)現(xiàn)DispatcherServlet里面根本沒有service這個(gè)方法,這個(gè)時(shí)候找到它的父類FrameworkServlet 琼梆,
doDispatch
,最主要的方法扣猫,用來分發(fā)請(qǐng)求勺远,核心的邏輯都在這里面(截圖有限,自己看源碼吧)
主要的:
1.checkMultipart
方法檢查是否是二進(jìn)制的請(qǐng)求(文件上傳的請(qǐng)求)
2.mappingHandler=getHandler(request)
返回的是HandlerExecutionChain
(處理執(zhí)行鏈)
再看DispatcherServlet.properties
其實(shí)就是包裝了不同的Mapping來判斷通過何種方式來配置。
HandlerExecutionChain
(處理執(zhí)行鏈)包含兩部分內(nèi)容,一部分是請(qǐng)求對(duì)應(yīng)的控制器,一部分是攔截器,真正執(zhí)行handle之前,有一系列操作,例如數(shù)據(jù)轉(zhuǎn)換,格式化,數(shù)據(jù)驗(yàn)證這些,都是由攔截器來做的
另外需要注意的是,假如你自定義了n個(gè)攔截器,會(huì)發(fā)現(xiàn)HandlerExecutionChain
會(huì)有n+1個(gè)攔截器,說明有一個(gè)是他內(nèi)部有的,從這里我們可以知道它的執(zhí)行順序,比如這里要先執(zhí)行攔截器,再執(zhí)行我們控制器,所以這個(gè)東西被稱為處理執(zhí)行鏈
3.ha = getHandlerAdapter(mappedHandler.getHandler());
![Uploading applyPreHandler_524696.png . . .]
HandlerAdapater
(處理器適配器)恬偷,用來執(zhí)行handler(控制器,即contorller)
這里判斷handler適不適合這個(gè)RequestMappingAdapter
肆良,適合就返回
if(ha.supports(handler))
return ha;
獲取方法類型
String method = reqyest,getMethod();
if(!mappedHandler.applyPreHandle(processedRequest, response)){
return;
}
這里主要遍歷攔截器。
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
這里去調(diào)用handler
方法曲秉,這個(gè)方法會(huì)做很多事情承二,比如參數(shù)自動(dòng)裝入。
然后是
@RequestMapping(value = "/golist.do")
public ModelAndView golist(HttpServletRequest request) {
return new ModelAndView("/views/module/advise/list.jsp");
}
再繼續(xù)
//默認(rèn)視圖名稱
applyDefaultViewName(request, mv);
像下面這個(gè) 返回的只有model
沒有 view
@RequestMapping(value = "/saveEntity.do")
public @ResponseBody AjaxResult saveByEntity(HttpServletRequest request, Advise entity) {
LoginUser loginUser = LoginUserUtil.getCurrentUser(request);
adviseService.saveEntity(loginUser, entity);
return AjaxResult.warpAjaxResult(true);
}
繼續(xù)往下
mappedHandler.applyPostHandle(processedRequest, response, mv);
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv)
throws Exception
{
if(getInterceptors() == null)
return;
for(int i = getInterceptors().length - 1; i >= 0; i--)
{
HandlerInterceptor interceptor = getInterceptors()[i];
interceptor.postHandle(request, response, handler, mv);
}
}
從這里我們知道,Interceptor
的執(zhí)行順序是反過來的:如圖
再繼續(xù)
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception)
throws Exception
{
boolean errorView = false;
if(exception != null)
if(exception instanceof ModelAndViewDefiningException)
{
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException)exception).getModelAndView();
} else
{
Object handler = mappedHandler == null ? null : mappedHandler.getHandler();
mv = processHandlerException(request, response, handler, exception);
errorView = mv != null;
}
if(mv != null && !mv.wasCleared())
{
render(mv, request, response);
if(errorView)
WebUtils.clearErrorRequestAttributes(request);
} else
if(logger.isDebugEnabled())
logger.debug((new StringBuilder()).append("Null ModelAndView returned to DispatcherServlet with name '").append(getServletName()).append("': assuming HandlerAdapter completed request handling").toString());
if(WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted())
return;
if(mappedHandler != null)
mappedHandler.triggerAfterCompletion(request, response, null);
}
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response)
throws Exception
{
Locale locale = localeResolver.resolveLocale(request);
response.setLocale(locale);
View view;
if(mv.isReference())
{
view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
if(view == null)
throw new ServletException((new StringBuilder()).append("Could not resolve view with name '").append(mv.getViewName()).append("' in servlet with name '").append(getServletName()).append("'").toString());
} else
{
view = mv.getView();
if(view == null)
throw new ServletException((new StringBuilder()).append("ModelAndView [").append(mv).append("] neither contains a view name nor a ").append("View object in servlet with name '").append(getServletName()).append("'").toString());
}
if(logger.isDebugEnabled())
logger.debug((new StringBuilder()).append("Rendering view [").append(view).append("] in DispatcherServlet with name '").append(getServletName()).append("'").toString());
try
{
//這里決定究竟是轉(zhuǎn)發(fā)還是重定向,或者說變成其他視圖
view.render(mv.getModelInternal(), request, response);
}
catch(Exception ex)
{
if(logger.isDebugEnabled())
logger.debug((new StringBuilder()).append("Error rendering view [").append(view).append("] in DispatcherServlet with name '").append(getServletName()).append("'").toString(), ex);
throw ex;
}
}
public void render(Map model, HttpServletRequest request, HttpServletResponse response)
throws Exception
{
if(logger.isTraceEnabled())
logger.trace((new StringBuilder()).append("Rendering view with name '").append(beanName).append("' with model ").append(model).append(" and static attributes ").append(staticAttributes).toString());
Map mergedModel = createMergedOutputModel(model, request, response);
prepareResponse(request, response);
renderMergedOutputModel(mergedModel, request, response);
}