一、流程圖
二、主要流程介紹:
DispatcherServlet:作為springmvc最重要的一部分,它
本身也是一個Servlet。它
負責調用HandlerMapping處理我們編寫的handler,傳回HandlerExecutionChain對象,再利用handler比對到合适的HandlerAdapter,使用這個HandlerAdapter對象處理handler,最終傳回一個ModelAndView對象,DispatcherServlet又請求ViewResolver對視圖進行解析,渲染,響應給使用者。- handler(用Object來接收的) :就是我們自己寫的Contorller。我們要使用springmvc來處理,一般有三種方式:第一種是 實作Controller接口 ,第二種可以 實作HttpRequestHandler接口 ,第三種就是 走@RequestMapping注解方式 。這三種方式會分别使用不同的HandlerMapping來處理,傳回的handler類型也不一樣(下面會說),是以handler會使用Object來接收
- HandlerExecutionChain :裡面封裝了 handler 和 HandlerInterceptor的List集合
,
FrameworkServlet又繼承了HttpServlet,
并覆寫了HttpServlet的service(HttpServletRequest request, HttpServletResponse response)方法,FrameworkServlet的service方法也涉及到調用,調用後還做了很多初始化的工作,但這些不重要,重點是它會調用doService方法,FrameworkServlet的doService方法是個抽象方法,是以直接轉到它的實作類DispatcherServlet中去,DispatcherServlet的doService方法又會做很多初始化的工作,向request域儲存很多屬性這些,但重點是他會調用本類的
doDispatch(request, response)方法,這個才是重點。如何調用到doDispatch方法的簡圖
三、源碼分析
DispatcherServlet的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 {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 1、調用處理器映射器(HandlerMapping),得到HandlerExecutionChain對象
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// 2、根據我們編寫的Contorller得到比對到适合的處理器擴充卡
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 (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 執行每個攔截器的preHandle方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
/*
3、利用處理器擴充卡,執行我們編寫的Contorller方法,
并進一步處理,返會ModelAndView對象 */
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(request, mv);
// 執行每個攔截器的postHandle方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
// 對自定義的異常處理器進行捕獲
catch (Exception ex) {
dispatchException = ex;
}
// 3、處理結果(頁面渲染),這裡過了,基本主要流程就走完了
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
// 異常時執行攔截器的afterCompletion方法
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
// 錯誤時也會執行攔截器的afterCompletion方法
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, 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);
}
}
}
}
分析:
核心1(請求 HandlerMapping擷取HandlerExecutionChain對象 ):
mappedHandler =getHandler(processedRequest);protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
解析:這個方法裡,會先周遊handlerMapping這個List集合(這個集合裡裝了所有的HandlerMapping對象(
BeanNameUrlHandlerMapping和
RequestMappingHandlerMapping)),然後依次執行HandlerMapping(HandlerMapping是所有處理器映射器的頂層接口)的getHandler(request)方法,
- BeanNameUrlHandlerMapping: 會處理 xml方式配置的Controller ,這種方式傳回的handler包括 處理器攔截器的集合 和 自己配置的Controller對象,且用他的頂層接口來接收 。
- RequestMappingHandlerMapping: 會處理 注解方式配置的Contorller ,這種方式傳回的handler包括 處理器攔截器(HandlerInterceptor)的集合 和 HandlerMethod對象 ( HandlerMethod裡面又封裝了處理方法的Method對象和我們寫的Contorller對象 )
核心2(比對到handler的HandlerAdapter):
HandlerAdapter ha =getHandlerAdapter(mappedHandler.getHandler());protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
if (ha.supports(handler)) {
return ha;
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
解析:這個方法接收的參數就是封裝在HandlerExecutionChain裡面的handler。首先,它會先周遊HandlerAdapter這個List集合(這個集合裡裝了所有的HandlerAdapter對象(
HttpRequestHandlerAdapter和
SimpleControllerHandlerAdapter和
RequestMappingHandlerAdapter)),然後
依次執行HandlerAdapter的supports(handler)方法,來判斷傳入的handler會适配哪一個HandlerAdapter,最終傳回這個比對的HandlerAdapter。- HttpRequestHandlerAdapter: 處理實作了HttpRequestHandler接口的自己寫的控制器
- SimpleControllerHandlerAdapter: 處理實作了Conroller接口的自己寫的控制器
- RequestMappingHandlerAdapter: 處理使用注解(@RequestMapping)方式的自己寫的控制器
核心3(HandlerAdapter處理handler,傳回ModelAndView對象):
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());解析:調用HandlerAdapter的handle方法,對handler進行處理。這部分源碼很多,而且比較複雜。在這方法裡面主要是
先調用了我們編寫的處理方法并擷取其傳回值,然後部分源碼如下,它會先周遊returnValueHandler,(這是個存儲傳回值處理器(
HandlerMethodReturnValueHandler)的List集合,裡面存了13個實作類對象,畢竟傳回值會有很多種情況)
将傳回值與傳回值處理器進行比對,比對成功後用這個HandlerMethodReturnValueHandler的handleReturnValue方法對傳回值進行處理(就是
将傳回值裝進ModelAndViewContainer這個對象中,
ModelAndViewContainer對象裡面裝了一個View和一個ModelMap,View用來裝視圖路徑,ModelMap用來裝資料(這個資料最終會放到request域中去)),最後再
new一個ModelAndView對象,将ModelAndViewContainer裡的View和ModelMap裝進去,傳回ModelAndView對象private HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) {
for (HandlerMethodReturnValueHandler returnValueHandler : returnValueHandlers) {
if (logger.isTraceEnabled()) {
logger.trace("Testing if return value handler [" + returnValueHandler + "] supports [" +
returnType.getGenericParameterType() + "]");
}
if (returnValueHandler.supportsReturnType(returnType)) {
return returnValueHandler;
}
}
return null;
}
核心4(請求ViewResolver對ModelAndView解析,然後頁面渲染):
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,
HttpServletRequest request) throws Exception {
for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}
return null;
}
這一部分隻是周遊List<ViewResolver>,利用合适的視圖解析器,解析出來View對象。之後會利用這個
View對象的render方法來渲染,渲染做的就是
取出ModelMap裡面資料放進request域中,和
對視圖名加上前字尾,利用request擷取到RequestDispatcher對象,然後forward轉發到對應的視圖去。(InternalResourceView裡的部分渲染源碼,看中文解釋就行)@Override
protected void renderMergedOutputModel(
Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
// 取出model裡的資料儲存到request域中
exposeModelAsRequestAttributes(model, request);
// Expose helpers as request attributes, if any.
exposeHelpers(request);
// 擷取實體視圖位址(就是轉發路徑)
String dispatcherPath = prepareForRendering(request, response);
// (擷取RequestDispatcher以友善後面的轉發)
RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
if (rd == null) {
throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
"]: Check that the corresponding file exists within your web application archive!");
}
// If already included or response already committed, perform include, else forward.
if (useInclude(request, response)) {
response.setContentType(getContentType());
if (logger.isDebugEnabled()) {
logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
}
// 請求轉發
rd.include(request, response);
}
渲染結束,在調用攔截器的afterCompletion方法。到這裡基本節結束了 最後,說一下攔截器的執行順序(都在doDispatch裡調用,然後在HandlerExecutionChain類中執行)
(1)處理器前:// 調用(DispatcherServlet的doDispatch中)
if (!mappedHandler.applyPreHandle(processedRequest, response)) { //調用
return;
}
//執行(HandlerExecutionChain類中)
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (getInterceptors() != null) {
for (int i = 0; i < getInterceptors().length; i++) {
HandlerInterceptor interceptor = getInterceptors()[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
看上面的源碼知道他會在處理前調用,執行
順序也是從0索引開始,傳回true就放行,傳回false就執行攔截器的afterCompletion方法。最後對interceptorIndex的索引值指派(這個很重要,它會涉及到有很多攔截器時攔截器後兩個方法的分别執行順序,這個索引也是用來保證攔截器的afterCompletion的調用)
(2)處理後渲染前// 調用(DispatcherServlet的doDispatch中)
mappedHandler.applyPostHandle(processedRequest, response, mv);
//執行(HandlerExecutionChain類中)
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, this.handler, mv);
}
}
這一部分執行順序就變了,他會先
從interceptorIndex這個索引開始向前周遊攔截器,然後執行它的postHandle方法 (3) 渲染後// 調用(DispatcherServlet的doDispatch中)
// 3、處理結果(頁面渲染),最後會執行攔截器
processDispatchResult(processedRequest, response, mappedHdler, mv, dispatchException);
catch (Exception ex) {
// 異常時執行攔截器的afterCompletion方法
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
// 錯誤時也會執行攔截器的afterCompletion方法
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
}
//==================================================================================
//執行(HandlerExecutionChain類中)
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
throws Exception {
if (getInterceptors() == null) {
return;
}
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = getInterceptors()[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
攔截器的afterCompletion的方法是一定會調用的,捕獲了異常或者錯誤會調用,沒有捕時在渲染結束也會調用。它的執行順序和攔截器的postHandle執行順序一樣 結論: - 某個攔截器的preHandle執行了且傳回為true,那麼它的afterCompletion一定會執行
- preHandle方法按順序執行,postHandle和afterCompletion反序調用
- 當某一個的攔截器的preHandle方法反回了false,會進入到triggerAfterCompletion(request, response, null); 再根據目前的interceptorIndex索引值,執行前面傳回為true的攔截器的afterCompletion方法
以上就是關于springmvc的執行流程的源碼分析了,因為本人也剛學springmvc,是以了解可能也會存在錯誤,如果有說錯了的地方,希望大家指出來,一起進步。