點滴記載,點滴進步,願自己更上一層樓。
經過前面幾部分的分享,springmvc的基本用法大緻講完。接下來分析源碼,看看到底它是怎麼做的,為什麼這樣幹就能執行,以及攔截器為什麼在Handler執行以前執行,攔截器的執行流程為什麼是先preHandle先順序執行,其他的是倒叙執行。
都知道springmvc項目中web.xml有一項配置------配置前端控制器,DispatchServlet。
可見所有的請求,都會經他來轉發到對應的Handler。
下面是總結的流程圖,沒有畫圖功底,湊合着看吧。
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
文字叙述
1 使用者浏覽器發起請求
2 前端控制器DispatcherServlet首先會去請求Handler(也就是Controller),
怎麼請求Handler----通過查找HandlerMapping(裡面有xml或者注解方式配置的Handler映射資訊資訊)來比對使用者請求url對應的Handler,
将查找到的請求資訊,放入到執行鍊HandlerExecutionChain中,然後在放入該url對應的攔截器資訊。
然後将執行鍊HandlerExecutionChain傳回給前端控制器DispatcherServlet
3 前端控制器DispatcherServlet通過請求到的handler,再請求處理器擴充卡HandlerAdapter去執行handler,
::: 執行之前需要先請求執行鍊中的攔截器的preHandle方法進行某些請求校驗等。
4 處理器擴充卡執行handler後傳回給前端控制器DispatcherServlet一個ModelAndView(裡面放有視圖資訊,模型資料資訊)
::: 執行攔截器的postHandle方法
5 前端控制器DispatcherServlet請求視圖解析器解析視圖,根據邏輯名(xxxx/xxxx/xxxx.jsp)解析成真正的視圖view(jsp,ftl等)
6 視圖解析器解析完成後,傳回給前端控制器DispatcherServlet一個View
7 前端控制器DispatcherServlet進行視圖渲染,将模型資料填充到request中
8 響應使用者請求,展示jsp等視圖資訊。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
看完上面的執行過程,其實過程也挺多的,但是裡面除了handler,攔截器,jsp等需要程式員來做以外,其他的要不配置一下就行,要不就完全是架構的東西,不用程式員編寫,但是了解下原理還是必要的。
下面開始源碼解讀部分。
既然web.xml中配置了DispatchServlet,是以入口一定在這個類裡面,主要的需要看的方法是裡面的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 err = null;
Exception dispatchException = null;
try {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
mappedHandler = this.getHandler(processedRequest);
if(mappedHandler == null || mappedHandler.getHandler() == null) {
this.noHandlerFound(processedRequest, response);
return;
}
HandlerAdapter ex = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if(isGet || "HEAD".equals(method)) {
long lastModified = ex.getLastModified(request, mappedHandler.getHandler());
if(this.logger.isDebugEnabled()) {
this.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;
}
try {
err = ex.handle(processedRequest, response, mappedHandler.getHandler());
} finally {
if(asyncManager.isConcurrentHandlingStarted()) {
return;
}
}
this.applyDefaultViewName(request, err);
mappedHandler.applyPostHandle(processedRequest, response, err);
} catch (Exception var27) {
dispatchException = var27;
}
this.processDispatchResult(processedRequest, response, mappedHandler, err, dispatchException);
} catch (Exception var28) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var28);
} catch (Error var29) {
this.triggerAfterCompletionWithError(processedRequest, response, mappedHandler, var29);
} finally {
if(asyncManager.isConcurrentHandlingStarted()) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
return;
}
if(multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
其中
mappedHandler = this.getHandler(processedRequest);
對應的就是就是第二步:前端控制器請求handler,傳回一個執行鍊,
具體是怎麼處理的,來看
getHandler(processedRequest);源碼。
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Iterator var2 = this.handlerMappings.iterator();
HandlerExecutionChain handler;
do {
if(!var2.hasNext()) {
return null;
}
HandlerMapping hm = (HandlerMapping)var2.next();
if(this.logger.isTraceEnabled()) {
this.logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name \'" + this.getServletName() + "\'");
}
handler = hm.getHandler(request);
} while(handler == null);
return handler;
}
代碼中的 Iterator var2 = this.handlerMappings.iterator(); 中的handlerMappings是在你初次請求後,spring加載的配置的映射資訊,
下面來看看 handlerMapping中的映射資訊。
可以看出框中的部分,裡面放置了所有的配置了@RequestMapping()的handler的映射資訊
"{[/helloWorld],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" -> "public org.springframework.web.servlet.ModelAndView com.soft.controller.TestController.helloWorld(javax.servlet.http.HttpServletRequest)"
上面這個是copy出來的一條完整的資訊,包含了handler mapping資訊。
我現在的請求是 http://localhost:8080/helloWorld,
controller代碼
package com.soft.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
/**
* Created by xuweiwei on 2017/8/19.
*/
@Controller
public class TestController {
@RequestMapping(value = "/helloWorld")
public ModelAndView helloWorld(HttpServletRequest request){
String name = request.getParameter("name");
System.out.println(name);
ModelAndView modelAndView = new ModelAndView();
// modelAndView.addObject("msg","hello world!!!!!!!");
modelAndView.addObject("msg", name);
modelAndView.setViewName("test/helloworld");
return modelAndView;
}
}
是以它請求到的一定是這個handler
可以看到框中的内容正是上面的controller。
注意到這塊代碼中還有一塊兒邏輯處理,
handler = hm.getHandler(request);
下面來看看這塊都幹了些什麼事情。
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = this.getHandlerInternal(request);
if(handler == null) {
handler = this.getDefaultHandler();
}
if(handler == null) {
return null;
} else {
if(handler instanceof String) {
String handlerName = (String)handler;
handler = this.getApplicationContext().getBean(handlerName);
}
return this.getHandlerExecutionChain(handler, request);
}
}
這裡就是在尋找對應的handler,沒找到傳回為null, getHandler(processedRequest);中的循環繼續執行,直到找到對應的handler為止,最後當找到對應的的handler以後會調用,his.getHandlerExecutionChain(handler, request);方法,來放置執行該handler需要放置的東西。
下面來看看,都放了什麼東東。
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = handler instanceof HandlerExecutionChain?(HandlerExecutionChain)handler:new HandlerExecutionChain(handler);
chain.addInterceptors(this.getAdaptedInterceptors());
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
Iterator var5 = this.mappedInterceptors.iterator();
while(var5.hasNext()) {
MappedInterceptor mappedInterceptor = (MappedInterceptor)var5.next();
if(mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
return chain;
}
可以看到這裡最要就是放了攔截器到執行鍊中去,到此第2部執行結束。傳回給前端控制器一個執行鍊(HandlerExecutionChain),裡面包含了handler資訊,攔截器資訊。
然後再回到前端控制器的doDispatch(HttpServletRequest request, HttpServletResponse response)代碼中去。
執行完請求handler請求後,開始請求處理器處理器擴充卡HandlerAdapter對應代碼部分。
HandlerAdapter ex = this.getHandlerAdapter(mappedHandler.getHandler());
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
Iterator var2 = this.handlerAdapters.iterator();
HandlerAdapter ha;
do {
if(!var2.hasNext()) {
throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
ha = (HandlerAdapter)var2.next();
if(this.logger.isTraceEnabled()) {
this.logger.trace("Testing handler adapter [" + ha + "]");
}
} while(!ha.supports(handler));
return ha;
}
代碼也沒什麼,就是在找handler對應的擴充卡。然後傳回給前端控制器,然後前端控制器,調用擴充卡的handle方法(也就是請求處理器擴充卡執行handler)。也就是下面這句代碼。
err = ex.handle(processedRequest, response, mappedHandler.getHandler());
但是在請求執行handler之前還有一句代碼比較重要。
if(!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
這個mappedHandler.applyPreHandle就是在做攔截器的攔截操作(prehandle方法),如果傳回為false直接return掉,不在繼續執行下面的代碼,這就是springmvc的攔截器的原理。這就是為什麼可以攔截請求。去瞄瞄看都有什麼東東。
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
if(this.getInterceptors() != null) {
for(int i = 0; i < this.getInterceptors().length; this.interceptorIndex = i++) {
HandlerInterceptor interceptor = this.getInterceptors()[i];
if(!interceptor.preHandle(request, response, this.handler)) {
this.triggerAfterCompletion(request, response, (Exception)null);
return false;
}
}
}
return true;
}
可以看到這裡是在循環着執行執行鍊中放入的需要執行的攔截器的preHandle方法(正叙執行)。如果碰到一個攔截器傳回為false,則直接執行triggerAfterCompletion,
應該都還記得攔截器有三個方法,preHandle postHandle afterCompletion 然而,這個方法就執行,afterCompletion 。反正也沒事再進去瞄瞄怎麼執行。
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception {
if(this.getInterceptors() != null) {
for(int i = this.interceptorIndex; i >= 0; --i) {
HandlerInterceptor interceptor = this.getInterceptors()[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
} catch (Throwable var7) {
logger.error("HandlerInterceptor.afterCompletion threw exception", var7);
}
}
}
}
可以看到确實在執行着攔截器的 afterCompletion 方法,但是這裡面的循環不再是正叙,而是倒叙,這也就是為什麼前一篇部落格得出的結論,afterCompletion 為倒叙執行。
看到下面這張圖的執行結果就恍然大悟了。
前端控制器執行handler之前,執行攔截器操作到此執行完畢。然後才是真正的執行handler。
接下來看下面這塊代碼
err = ex.handle(processedRequest, response, mappedHandler.getHandler());
看看它的源碼,源碼在 AbstractHandlerMethodAdapter.java中。
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return this.handleInternal(request, response, (HandlerMethod)handler);
}
繼續跟進,發現真正的源碼在,RequestMappingHandlerAdapter.java的handleInternal方法裡面
protected final ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
if(this.getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
this.checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
} else {
this.checkAndPrepare(request, response, true);
}
if(this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if(session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized(mutex) {
return this.invokeHandleMethod(request, response, handlerMethod);
}
}
}
return this.invokeHandleMethod(request, response, handlerMethod);
}
invokeHandleMethod看着很眼熟,java反射機制裡面執行某個方法用的就是invoke。
跟進去看看
private ModelAndView invokeHandleMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
WebDataBinderFactory binderFactory = this.getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = this.getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod requestMappingMethod = this.createRequestMappingMethod(handlerMethod, binderFactory);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
if(asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer)asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
if(this.logger.isDebugEnabled()) {
this.logger.debug("Found concurrent result value [" + result + "]");
}
requestMappingMethod = requestMappingMethod.wrapConcurrentResult(result);
}
requestMappingMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);
return asyncManager.isConcurrentHandlingStarted()?null:this.getModelAndView(mavContainer, modelFactory, webRequest);
}
可以看到在執行之前做了一堆的事前準備工作。其他的可以不用理會,主要看
requestMappingMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);做了一些什麼事情。
public final void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);
this.setResponseStatus(webRequest);
if(returnValue == null) {
if(this.isRequestNotModified(webRequest) || this.hasResponseStatus() || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
} else if(StringUtils.hasText(this.responseReason)) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
try {
this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);
} catch (Exception var6) {
if(this.logger.isTraceEnabled()) {
this.logger.trace(this.getReturnValueHandlingErrorMessage("Error handling return value", returnValue), var6);
}
throw var6;
}
}
代碼中大部分還是在校驗,設值,隻有invokeForRequest它在幹着實事。再看看。它在 InvocableHandlerMethod.java 中
public final Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
if(this.logger.isTraceEnabled()) {
StringBuilder returnValue = new StringBuilder("Invoking [");
returnValue.append(this.getBeanType().getSimpleName()).append(".");
returnValue.append(this.getMethod().getName()).append("] method with arguments ");
returnValue.append(Arrays.asList(args));
this.logger.trace(returnValue.toString());
}
Object returnValue1 = this.invoke(args);
if(this.logger.isTraceEnabled()) {
this.logger.trace("Method [" + this.getMethod().getName() + "] returned [" + returnValue1 + "]");
}
return returnValue1;
}
終于找到了,Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);這句在給需要執行的handler的方法準備參數資訊。然後
Object returnValue1 = this.invoke(args);來執行方法。
總算找到了,曲曲折折饒了一大彎。最後傳回一個ModelAndView給前端控制器。
然後開始執行攔截器的postHandle 也就是這句---- mappedHandler.applyPostHandle(processedRequest, response, err);
源碼
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
if(this.getInterceptors() != null) {
for(int i = this.getInterceptors().length - 1; i >= 0; --i) {
HandlerInterceptor interceptor = this.getInterceptors()[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
看的出來跟 triggerAfterCompletion 的執行有相似之處,都是倒叙執行。
是以攔截器那篇部落格的結論,所有的preHandle方法都為true的時候postHandle才執行,并且是倒叙執行。這就是原因,這就是原理。
最後前端控制器 開始請求視圖解析器解析視圖,渲染視圖等等
this.processDispatchResult(processedRequest, response, mappedHandler, err, 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) {
this.logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException)exception).getModelAndView();
} else {
Object handler = mappedHandler != null?mappedHandler.getHandler():null;
mv = this.processHandlerException(request, response, handler, exception);
errorView = mv != null;
}
}
if(mv != null && !mv.wasCleared()) {
this.render(mv, request, response);
if(errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
} else if(this.logger.isDebugEnabled()) {
this.logger.debug("Null ModelAndView returned to DispatcherServlet with name \'" + this.getServletName() + "\': assuming HandlerAdapter completed request handling");
}
if(!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
if(mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, (Exception)null);
}
}
}
這裡的代碼分三塊,一塊看看執行Handler結果有沒有異常,有的話處理異常,注意這裡可以自定義異常,來統一處理。
另一塊就是說的請求視圖解析器解析,渲染視圖等操作。
最後又看到了眼熟的 triggerAfterCompletion 了,這裡不在看它。
主要看 this.render(mv, request, response); 看它是怎麼請求視圖解析器,渲染視圖的。
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
Locale locale = this.localeResolver.resolveLocale(request);
response.setLocale(locale);
View view;
if(mv.isReference()) {
view = this.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 \'" + this.getServletName() + "\'");
}
} else {
view = mv.getView();
if(view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " + "View object in servlet with name \'" + this.getServletName() + "\'");
}
}
if(this.logger.isDebugEnabled()) {
this.logger.debug("Rendering view [" + view + "] in DispatcherServlet with name \'" + this.getServletName() + "\'");
}
try {
view.render(mv.getModelInternal(), request, response);
} catch (Exception var7) {
if(this.logger.isDebugEnabled()) {
this.logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name \'" + this.getServletName() + "\'", var7);
}
throw var7;
}
}
這裡面,前一個if else就是在請求視圖解析器。可以看看resolveViewName方法是怎麼通過解析器獲得視圖view的。
protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception {
Iterator var5 = this.viewResolvers.iterator();
View view;
do {
if(!var5.hasNext()) {
return null;
}
ViewResolver viewResolver = (ViewResolver)var5.next();
view = viewResolver.resolveViewName(viewName, locale);
} while(view == null);
return view;
}
看看即可,不是設麼高深的代碼。
擷取到view以後 開始對視圖進行渲染,也就是将模型中的資料填充到request中去,
進入到 AbstractView.java 中
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
if(this.logger.isTraceEnabled()) {
this.logger.trace("Rendering view with name \'" + this.beanName + "\' with model " + model + " and static attributes " + this.staticAttributes);
}
Map mergedModel = this.createMergedOutputModel(model, request, response);
this.prepareResponse(request, response);
this.renderMergedOutputModel(mergedModel, request, response);
}
沒什麼好看的,繼續跟蹤,renderMergedOutputModel方法。
protected abstract void renderMergedOutputModel(Map<String, Object> var1, HttpServletRequest var2, HttpServletResponse var3) throws Exception;
發現是個抽象方法,記得springmvc.xml中配置的視圖解析器是 InternalResourceViewResolver 是以它對應的 View 是 InternalResourceView
是以會調到這個類裡面的renderMergedOutpitModel方法中,上代碼
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest requestToExpose = this.getRequestToExpose(request);
this.exposeModelAsRequestAttributes(model, requestToExpose);
this.exposeHelpers(requestToExpose);
String dispatcherPath = this.prepareForRendering(requestToExpose, response);
RequestDispatcher rd = this.getRequestDispatcher(requestToExpose, dispatcherPath);
if(rd == null) {
throw new ServletException("Could not get RequestDispatcher for [" + this.getUrl() + "]: Check that the corresponding file exists within your web application archive!");
} else {
if(this.useInclude(requestToExpose, response)) {
response.setContentType(this.getContentType());
if(this.logger.isDebugEnabled()) {
this.logger.debug("Including resource [" + this.getUrl() + "] in InternalResourceView \'" + this.getBeanName() + "\'");
}
rd.include(requestToExpose, response);
} else {
if(this.logger.isDebugEnabled()) {
this.logger.debug("Forwarding to resource [" + this.getUrl() + "] in InternalResourceView \'" + this.getBeanName() + "\'");
}
rd.forward(requestToExpose, response);
}
}
}
先來看看裡面的exposeModelAsRequestAttributes方法
protected void exposeModelAsRequestAttributes(Map<String, Object> model, HttpServletRequest request) throws Exception {
Iterator var3 = model.entrySet().iterator();
while(var3.hasNext()) {
Entry entry = (Entry)var3.next();
String modelName = (String)entry.getKey();
Object modelValue = entry.getValue();
if(modelValue != null) {
request.setAttribute(modelName, modelValue);
if(this.logger.isDebugEnabled()) {
this.logger.debug("Added model object \'" + modelName + "\' of type [" + modelValue.getClass().getName() + "] to request in view with name \'" + this.getBeanName() + "\'");
}
} else {
request.removeAttribute(modelName);
if(this.logger.isDebugEnabled()) {
this.logger.debug("Removed model object \'" + modelName + "\' from request in view with name \'" + this.getBeanName() + "\'");
}
}
}
}
前面說的什麼渲染視圖,将模型中的資料填充到request中去,就是這裡實作了,前面的ModelAndView中的模型資料都已經放入到這個傳入的map中去了,然後什麼封包頭等等頁面需要的,最後統一放入到request中去。
看完了 exposeModelAsRequestAttributes 再看 接下來的代碼,
this.exposeHelpers(requestToExpose);對應的是空代碼塊,不在說了。
String dispatcherPath = this.prepareForRendering(requestToExpose, response); // 得到view所在的路徑 Dispatcher要跳轉的路徑
RequestDispatcher rd = this.getRequestDispatcher(requestToExpose, dispatcherPath); 得到一個Dispatcher
if(this.useInclude(requestToExpose, response)) {
response.setContentType(this.getContentType());
if(this.logger.isDebugEnabled()) {
this.logger.debug("Including resource [" + this.getUrl() + "] in InternalResourceView \'" + this.getBeanName() + "\'");
}
rd.include(requestToExpose, response);
} else {
if(this.logger.isDebugEnabled()) {
this.logger.debug("Forwarding to resource [" + this.getUrl() + "] in InternalResourceView \'" + this.getBeanName() + "\'");
}
rd.forward(requestToExpose, response);
}
這裡設定跳轉的路徑,這個include和forword的具體差別,請看
http://blog.csdn.net/huo2007201019/article/details/7584241
這裡執行完畢後,就要執行攔截器的最後操作,以及一些final裡面的内容。
流程方面的源碼解析,完畢。
分析到最後一點的時候發現對servlet的知識忘了,以後要補補。
點選分享,點選進步,終會更上一層樓。
下節,springmvc的參數綁定源碼解析。