SpringMVC的執行流程網上有不少帖子都有講解,流程圖和文字描述都很詳細,可是你若是沒有經過具體源碼本身走一遍流程,其實只是死記硬背。因此想開個帖子從源碼角度再梳理一遍SpringMVC的執行流程,加深印象。java
SpringMVC採用的是前端控制器(Front Controller) + 各個業務處理器(Controller)來處理請求的。前端控制器來響應全部請求,經過必定的調度規則找到具體負責處理的業務處理器,並將請求委派給具體的業務處理器去執行業務邏輯,業務處理器返回給前端控制器模型數據model,最後前端控制器將model交給視圖View進行渲染。web
看源碼的同窗可能每每會陷入一個怪圈,剛開始看可能還能看懂,等到一層一層點進去會愈來愈暈,讓本身陷入了太多的細節中,而這些細節其實對主要流程並無多大影響,而後就埋頭研究。以後不得不又從頭開始看,又讓本身陷入了另外一個細節。其實看源碼開始時只是須要看一個大體的框架和思路,瞭解代碼的大體執行流程,千萬不要讓本身陷入到細節的泥潭中。因此本文是經過幾個關鍵的接口做爲切入點來梳理SpringMVC的執行流程,若是咱們把關鍵的接口弄懂了,也就瞭解了SpringMVC的執行流程。因此本文只是去了解接口功能,並不關注到具體的實現邏輯上。當咱們把大致流程瞭解後,以後就只是各個擊破具體的實現類了。以後做者還會經過本身來實現這些接口來處理本身定義的請求,結合具體的例子來理解。spring
閱讀SpringMVC源碼給我最大的感觸有兩點:編程
注:源碼版本爲 spring-webmvc-5.2.2.RELEASE.jar
json
public interface HandlerMapping { @Nullable HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception; }
HandlerMapping映射了請求與具體處理器的關係,能夠理解爲內存中有這樣一個內存數據 Map<request, Handler>,HandlerMapping就是根據請求從Map中找到Handler返回。HandlerExecutionChain只是將Handler和其對應的攔截器interceptors進行了包裝。mvc
前文所說的調度規則,經過請求的 HttpServletRequest 獲取具體的請求處理類,將請求處理類包裝成 HandlerExecutionChain 返回。其中 HandlerExecutionChain中的Object handler就是具體的請求處理類。app
public class HandlerExecutionChain { private final Object handler; @Nullable private HandlerInterceptor[] interceptors; @Nullable private List<HandlerInterceptor> interceptorList; }
咱們如今經過請求找到了具體的處理類,那麼咱們怎麼經過處理類去執行具體的方法呢?那麼就須要HandlerAdapter了。框架
public interface HandlerAdapter { /** * 經過方法 supports 判斷適配器是否適配這種類型的Handler,返回true則表明適配。 */ boolean supports(Object handler); /** * 若是適配則經過方法 handle 去讓 Object handler 執行具體的處理方法。 */ @Nullable ModelAndView handle(HttpServletRequest request, HttpServletResponse response , Object handler) throws Exception; long getLastModified(HttpServletRequest request, Object handler); }
HandlerAdapter 處理器的適配器,幫助前端控制器去執行處理器Handler中具體的處理業務,讓前端控制機不須要關注具體的執行細節,也就是說HandlerAdapter對前端控制機屏蔽了處理器執行的具體細節。jsp
public class ModelAndView { /** View instance or view name String. */ @Nullable private Object view; /** Model Map. */ @Nullable private ModelMap model;
對邏輯視圖名view和數據模型的封裝。
Object view爲一般爲String類型的邏輯視圖名。
ModelMap 爲MVC中Model的角色,底層爲Map類型。
public interface ViewResolver { @Nullable View resolveViewName(String viewName, Locale locale) throws Exception; }
解析邏輯視圖名viewName找到具體的View,前端控制器找到具體視圖View的嚮導。
public interface View { void render(@Nullable Map<String, ?> model, HttpServletRequest request , HttpServletResponse response) throws Exception; }
調用render方法經過數據模型渲染視圖。
請求參數中的 Map<String, ?> model 在SpringMVC中扮演Model的角色。
好比咱們想返回json格式的數據,那麼render方法邏輯就是將model轉爲json格式輸出。
或者咱們想返回jsp,那麼咱們就能夠model解析到具體的jsp頁面進行展現。
在SpringMVC中,DispatcherServlet做爲前端控制器,控制服務的具體執行流程,主要的執行流程代碼也都在這個類中。
下面是DispatcherServlet簡化的源碼,只包含了重要的執行流程,保留了關鍵的執行代碼,讀者能夠具體關鍵字進行搜索去找到具體的代碼行。
public class DispatcherServlet extends FrameworkServlet { protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HandlerExecutionChain mappedHandler = null; ModelAndView mv = null; mappedHandler = getHandler(processedRequest); HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); render(mv, request, response); } protected void render(ModelAndView mv, HttpServletRequest request , HttpServletResponse response) throws Exception { String viewName = mv.getViewName(); view = resolveViewName(viewName, mv.getModelInternal(), locale, request); view.render(mv.getModelInternal(), request, response); }
@Nullable protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { if (this.handlerMappings != null) { for (HandlerMapping mapping : this.handlerMappings) { HandlerExecutionChain handler = mapping.getHandler(request); if (handler != null) { return handler; } } } return null; }
SpringMVC在啓動的時候會掃描全部實現了HandlerMapping接口的類,並將這些類加入到容器中。
獲取處理器其實就是循環實現了HandlerMapping的類,調用getHandler()方法,找到了就中止並返回。
每種類型的Handler都有各自對應的HandlerMapping。好比SpirngMVC中默認的處理器爲 Controller,與之對於的HandlerMapping爲RequestMappingHandlerMapping。
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { if (this.handlerAdapters != null) { for (HandlerAdapter adapter : this.handlerAdapters) { if (adapter.supports(handler)) { return adapter; } } } }
邏輯和獲取處理器同樣,判斷邏輯就是前面提過的,只要supports方法返回true,則表明適配這個Handler。
同理也是一種Handler應該有與之對應的HandlerAdapter。與Controller對應的爲RequestMappingHandlerAdapter。
因此若是咱們要編寫自定義的處理器。那麼咱們須要本身的Handler類和與之對於的HandlerMapping和HandlerAdapter。
@Nullable protected View resolveViewName(String viewName, @Nullable Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception { if (this.viewResolvers != null) { for (ViewResolver viewResolver : this.viewResolvers) { View view = viewResolver.resolveViewName(viewName, locale); if (view != null) { return view; } } } return null; }
仍然是一樣的邏輯,全部的代碼都是面向接口來開發的。
SpringMVC支持各類各樣的視圖渲染,如JSP、json、freemarker、thymeleaf。ViewResolver就是這些視圖的嚮導,它告訴SpringMVC須要經過什麼方式去找到具體的視圖View。
每種視圖View都有本身對應的視圖解析器,例如FreeMarkerView對應的視圖解析器爲FreeMarkerViewResolver。
其實就一句代碼。
view.render(mv.getModelInternal(), request, response);
視圖渲染,做者剛開始看到這個詞,以爲好高大上。其實就是讓數據模型model應以什麼樣的方式來展現。
若是你想將model以json格式返回,那麼你就去實現View接口,把model轉爲json格式,而後寫入到響應類的輸出流便可。
ServletOutputStream out = response.getOutputStream(); baos.writeTo(json); out.flush();
本文只是經過幾個重要的接口來描述SpringMVC的執行流程,沒有具體分析實現類的邏輯。也想在這裏分享下本身看源碼的心得體會。看源碼時千萬不要讓本身陷入過深的業務邏輯中去,先看主要執行流程,重要的接口,好比以debug的方式先預覽下執行的方法棧,根據方法棧去定位。若是有哪些地方有誤或者有不一樣的理解,還請不吝賜教。