前言
好長時間就在想,SpringMVC框架入口就是一個簡單的servlet,是如何做到只是通過一些簡單的註解就能讓請求地址找到對應的方法,並且執行呢?註解又是如何解析的呢?
網上說的雲裏霧裏,什麼HandlerMapping
,什麼HandlerAdapter
還有視圖解析器?感覺好高大上的感覺一定很複雜把。但是這些組件是如何工作的,又是如何生成的呢?說實在的,現在的我也是懵懵懂懂。
1.SpringMVC初始化解析
現在我也不是很瞭解是怎麼工作的,既然不知道,那就從入口開始吧。入口就是一個DispatcherServlet
,既然是通過servlet
進行配置的,那麼一定遵循servlet
原理吧。
DispatcherServlet
負責完成的是SpringMVC具體內容,比如SpringMVC9大組件。
FrameworkServlet
負責完成容器上下文的建立。
HttpServletBean
進行初始化。
- 既然是servlet,那就找
init
方法了,執行HttpServletBean
的init
方法。 - 通過init方法調用
FrameworkServlet
的initServletBean
進行上下文初始化。 - 調用
initWebApplicationContext
方法進行初始化。這個方法中內容比較亂,設計到spring父子容器的內容,但是這裏就任務只是配置了SpringMVC,不存在父容器。 - 既然不存在父容器,那麼
wac
一定是null,那麼就會執行createWebApplicationContext
方法。這個方法是創建一個全新的spring容器,作爲SpringMVC的容器,(SpringMVC容器和spring容器其實不在一起); - 接着下面就直接按照流程跑就可以了,最後調用
wac.refresh
進行容器的初始化。容器初始化流程比較複雜,這裏完成的功能點有:- ioc容器初始化,掃描包,註解處理。生成
BeanDefinition
- ioc注入 等等
- ioc容器初始化,掃描包,註解處理。生成
- 容器初始化完成之後,SpringMVC進行初始化組件。
- SpringMVC有9大組件,包括
HandlerMapping
,HandlerAdapter
,等等都是在這裏進行初始化。
2.SpringMVC的工作流程
springMVC的工作流程,網上一搜一大堆。。隨意複製一段,如下:
1、用戶發送請求至前端控制器DispatcherServlet。
2、DispatcherServlet收到請求調用HandlerMapping處理器映射器。
3、處理器映射器找到具體的處理器(可以根據xml配置、註解進行查找),生成處理器對象及處理器攔截器(如果有則生成)一併返回給DispatcherServlet。
4、 DispatcherServlet調用HandlerAdapter處理器適配器。
5、HandlerAdapter經過適配調用具體的處理器(Controller,也叫後端控制器)。
6、Controller執行完成返回ModelAndView。
7、HandlerAdapter將controller執行結果ModelAndView返回給DispatcherServlet。
8、DispatcherServlet將ModelAndView傳給ViewReslover視圖解析器。
9、ViewReslover解析後返回具體View.
10、DispatcherServlet根據View進行渲染視圖(即將模型數據填充至視圖中)。
11、DispatcherServlet響應用戶。
想必大家一定都很熟悉,但是字一會就背下來了,但是真正的流程是啥樣子的呢?不廢話,上圖。
既然是servlet
那麼當請求進來,一定走service
方法,DispatchResult
的父類FrameworkServlet
中重寫了此方法。
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
processRequest(request, response);
}
else {
// 雖然會走這個方法,但是到最後還會走到當前類的 processRequest方法
super.service(request, response);
}
}
接着就直接跟着流程走就可以。接着看到最後這個流程,這段代碼有說明爲什麼是
DispatcherServlet
收到請求調用HandlerMapping
處理器映射器,DispatcherServlet
又是如何調用HandlerAdapter
處理器適配器的,視圖又是如何進行解析的等等。
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);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
// 這就是傳說中的 通過處理器映射器找到具體的處理器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
// 如果是get或head 方法, 調用getLastModified()獲取上次更新時間
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;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
// 這一段就是傳說中的 HandlerAdapter經過適配調用具體的處理器,通過反射調用Controller執行完成之後返回ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// 這裏就是交給視圖解析器進行解析
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", 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);
}
}
}
}