分析:
dispatcherServlet配置在web.xml中,一般都是分發所有請求。發送一個請求進入到dispatcherServlet的doDispatcher函數中
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
進入到getHandler,
/**
* Return the HandlerExecutionChain for this request.
* <p>Tries all handler mappings in order.
* @param request current HTTP request
* @return the HandlerExecutionChain, or {@code null} if no handler could be found
*/
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;
}
可以看出mappedHandler 是一個HandlerExecutionChain。
什麼是HandlerExecutionChain?JavaDoc解釋:Handler execution chain, consisting of handler object and any handler interceptors.
這個HandlerExecutionChain是由HandlerMapping 獲取到的。
什麼是HandlerMapping ?解釋:Interface to be implemented by objects that define a mapping between requests and handler objects
此時的handlerMapping裏有什麼?
getHandler()方法執行後 得到HandlerExecutionChain裏的handler是你請求的控制器。
注意:如果發送的請求沒有經過映射如a.html,mappedHandler 不爲null.因爲配置了
<mvc:default-servlet-handler />
靠的是handlerMapping裏的simpleUrlHandlerMapping(認爲請求的是靜態資源),得到HandlerExecutionChain裏的handler是DefaultServletHttpRequesthandler
如果沒有這個配置 則爲null.
接下來獲取HandlerAdapter
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
解釋:Interface that must be implemented for each handler type to handle a request
然後執行
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
/**
* Apply preHandle methods of registered interceptors.
* @return {@code true} if the execution chain should proceed with the
* next interceptor or the handler itself. Else, DispatcherServlet assumes
* that this interceptor has already dealt with the response itself.
*/
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
這個方法applyPreHandle()調用了攔截器的preHandler
接下來調用目標方法,執行HandlerAdapter對象的handle方法
HandlerAdapter作用:接過handlermapping解析請求得到的handler對象。在更精確的定位到能夠執行請求的方法。而且在調用目標方法過程中發生很多事情,如表單數據類型校驗,數據類型的轉換 ,格式化等
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
三個參數分別爲 請求(request current HTTP request),響應( response current HTTP response) ,映射的控制器(handler handler to use),返回一個ModelAndView
繼承HandlerAdapter接口的有
我這裏進入到AbstractHandlerMethodAdapter。裏面有handleInternal方法。Use the given handler method to handle the request.
然後通過mappedHandler調用攔截器postHandle方法。
mappedHandler.applyPostHandle(processedRequest, response, mv);
/**
* Apply postHandle methods of registered interceptors.
*/
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
處理視圖:
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
進入processDispatchResult
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
看到 判斷是否有異常,如果有,利用視圖解析器processHandlerException裏的HandlerExceptionResolver解析
之後渲染視圖(仍在processDispatchResult方法裏)
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
"': assuming HandlerAdapter completed request handling");
}
}
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
Locale locale = this.localeResolver.resolveLocale(request);
response.setLocale(locale);
View view;
if (mv.isReference()) {
// We need to resolve the view name.
view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
"' in servlet with name '" + getServletName() + "'");
}
}
else {
// No need to lookup: the ModelAndView object contains the actual View object.
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
"View object in servlet with name '" + getServletName() + "'");
}
}
// Delegate to the View object for rendering.
if (logger.isDebugEnabled()) {
logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
}
try {
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" +
getServletName() + "'", ex);
}
throw ex;
}
}
在這裏利用視圖解析器ViewResolver得到view對象,將邏輯視圖 變爲物理視圖。
最後調用攔截器的trigglerAfterCompletion(整個請求處理完畢回調方法,即在視圖渲染完畢時回調,如性能監控中我們可以在此記錄結束時間並輸出消耗時間,還可以進行一些資源清理,類似於try-catch-finally中的finally,但僅調用處理器執行鏈中preHandle返回true的攔截器的afterCompletion。)
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
以上是正常的流程。
如果發送一個請求,如a.html.如果在springMVC的配置文件裏沒有
<!-- 加載靜態資源 -->
<mvc:default-servlet-handler />
則404. 必須有這個配置 而且view裏有這個文件纔可以。
如果你配置了
<mvc:default-servlet-handler />
則必須配置
<!-- 配置返回信息編碼格式 -->
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain; charset=UTF-8</value>
<value>text/json; charset=UTF-8</value>
<value>text/html; charset=UTF-8</value>
<value>application/json; charset=UTF-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
不然 controller無法進入。參考這個:mvc:annotation-driven以及@Controller和@RequestMapping的那些事