原 springmvc----源码分析之springmvc执行流程

经过前面几部分的分享,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

所有的处理逻辑都在这个方法里面。源码奉上

 
  1. protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {

  2. HttpServletRequest processedRequest = request;

  3. HandlerExecutionChain mappedHandler = null;

  4. boolean multipartRequestParsed = false;

  5. WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

  6.  
  7. try {

  8. ModelAndView err = null;

  9. Exception dispatchException = null;

  10.  
  11. try {

  12. processedRequest = this.checkMultipart(request);

  13. multipartRequestParsed = processedRequest != request;

  14. mappedHandler = this.getHandler(processedRequest);

  15. if(mappedHandler == null || mappedHandler.getHandler() == null) {

  16. this.noHandlerFound(processedRequest, response);

  17. return;

  18. }

  19.  
  20. HandlerAdapter ex = this.getHandlerAdapter(mappedHandler.getHandler());

  21. String method = request.getMethod();

  22. boolean isGet = "GET".equals(method);

  23. if(isGet || "HEAD".equals(method)) {

  24. long lastModified = ex.getLastModified(request, mappedHandler.getHandler());

  25. if(this.logger.isDebugEnabled()) {

  26. this.logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);

  27. }

  28.  
  29. if((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {

  30. return;

  31. }

  32. }

  33.  
  34. if(!mappedHandler.applyPreHandle(processedRequest, response)) {

  35. return;

  36. }

  37.  
  38. try {

  39. err = ex.handle(processedRequest, response, mappedHandler.getHandler());

  40. } finally {

  41. if(asyncManager.isConcurrentHandlingStarted()) {

  42. return;

  43. }

  44.  
  45. }

  46.  
  47. this.applyDefaultViewName(request, err);

  48. mappedHandler.applyPostHandle(processedRequest, response, err);

  49. } catch (Exception var27) {

  50. dispatchException = var27;

  51. }

  52.  
  53. this.processDispatchResult(processedRequest, response, mappedHandler, err, dispatchException);

  54. } catch (Exception var28) {

  55. this.triggerAfterCompletion(processedRequest, response, mappedHandler, var28);

  56. } catch (Error var29) {

  57. this.triggerAfterCompletionWithError(processedRequest, response, mappedHandler, var29);

  58. } finally {

  59. if(asyncManager.isConcurrentHandlingStarted()) {

  60. mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);

  61. return;

  62. }

  63.  
  64. if(multipartRequestParsed) {

  65. this.cleanupMultipart(processedRequest);

  66. }

  67.  
  68. }

  69.  
  70. }

其中

mappedHandler = this.getHandler(processedRequest);

对应的就是就是第二步:前端控制器请求handler,返回一个执行链,

具体是怎么处理的,来看

getHandler(processedRequest);源码。

 
  1. protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {

  2. Iterator var2 = this.handlerMappings.iterator();

  3.  
  4. HandlerExecutionChain handler;

  5. do {

  6. if(!var2.hasNext()) {

  7. return null;

  8. }

  9.  
  10. HandlerMapping hm = (HandlerMapping)var2.next();

  11. if(this.logger.isTraceEnabled()) {

  12. this.logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name \'" + this.getServletName() + "\'");

  13. }

  14.  
  15. handler = hm.getHandler(request);

  16. } while(handler == null);

  17.  
  18. return handler;

  19. }

代码中的 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代码

 
  1. package com.soft.controller;

  2.  
  3. import org.springframework.stereotype.Controller;

  4. import org.springframework.web.bind.annotation.RequestMapping;

  5. import org.springframework.web.servlet.ModelAndView;

  6.  
  7. import javax.servlet.http.HttpServletRequest;

  8.  
  9. /**

  10. * Created by xuweiwei on 2017/8/19.

  11. */

  12. @Controller

  13. public class TestController {

  14.  
  15. @RequestMapping(value = "/helloWorld")

  16. public ModelAndView helloWorld(HttpServletRequest request){

  17. String name = request.getParameter("name");

  18. System.out.println(name);

  19. ModelAndView modelAndView = new ModelAndView();

  20. // modelAndView.addObject("msg","hello world!!!!!!!");

  21. modelAndView.addObject("msg", name);

  22. modelAndView.setViewName("test/helloworld");

  23. return modelAndView;

  24. }

  25. }

所以它请求到的一定是这个handler

可以看到框中的内容正是上面的controller。

注意到这块代码中还有一块儿逻辑处理,

handler = hm.getHandler(request);

下面来看看这块都干了些什么事情。

 
  1. public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {

  2. Object handler = this.getHandlerInternal(request);

  3. if(handler == null) {

  4. handler = this.getDefaultHandler();

  5. }

  6.  
  7. if(handler == null) {

  8. return null;

  9. } else {

  10. if(handler instanceof String) {

  11. String handlerName = (String)handler;

  12. handler = this.getApplicationContext().getBean(handlerName);

  13. }

  14.  
  15. return this.getHandlerExecutionChain(handler, request);

  16. }

  17. }

这里就是在寻找对应的handler,没找到返回为null,getHandler(processedRequest);中的循环继续执行,直到找到对应的handler为止,最后当找到对应的的handler以后会调用,his.getHandlerExecutionChain(handler, request);方法,来放置执行该handler需要放置的东西。

下面来看看,都放了什么东东。

 
  1. protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {

  2. HandlerExecutionChain chain = handler instanceof HandlerExecutionChain?(HandlerExecutionChain)handler:new HandlerExecutionChain(handler);

  3. chain.addInterceptors(this.getAdaptedInterceptors());

  4. String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);

  5. Iterator var5 = this.mappedInterceptors.iterator();

  6.  
  7. while(var5.hasNext()) {

  8. MappedInterceptor mappedInterceptor = (MappedInterceptor)var5.next();

  9. if(mappedInterceptor.matches(lookupPath, this.pathMatcher)) {

  10. chain.addInterceptor(mappedInterceptor.getInterceptor());

  11. }

  12. }

  13.  
  14. return chain;

  15. }

可以看到这里最要就是放了拦截器到执行链中去,到此第2部执行结束。返回给前端控制器一个执行链(HandlerExecutionChain),里面包含了handler信息,拦截器信息。

然后再回到前端控制器的doDispatch(HttpServletRequest request, HttpServletResponse response)代码中去。

执行完请求handler请求后,开始请求处理器处理器适配器HandlerAdapter对应代码部分。

HandlerAdapter ex = this.getHandlerAdapter(mappedHandler.getHandler());

 
  1. protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {

  2. Iterator var2 = this.handlerAdapters.iterator();

  3.  
  4. HandlerAdapter ha;

  5. do {

  6. if(!var2.hasNext()) {

  7. throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");

  8. }

  9.  
  10. ha = (HandlerAdapter)var2.next();

  11. if(this.logger.isTraceEnabled()) {

  12. this.logger.trace("Testing handler adapter [" + ha + "]");

  13. }

  14. } while(!ha.supports(handler));

  15.  
  16. return ha;

  17. }

代码也没什么,就是在找handler对应的适配器。然后返回给前端控制器,然后前端控制器,调用适配器的handle方法(也就是请求处理器适配器执行handler)。也就是下面这句代码。

err = ex.handle(processedRequest, response, mappedHandler.getHandler());
但是在请求执行handler之前还有一句代码比较重要。

 
  1. if(!mappedHandler.applyPreHandle(processedRequest, response)) {

  2. return;

  3. }

这个mappedHandler.applyPreHandle就是在做拦截器的拦截操作(prehandle方法),如果返回为false直接return掉,不在继续执行下面的代码,这就是springmvc的拦截器的原理。这就是为什么可以拦截请求。去瞄瞄看都有什么东东。

 
  1. boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {

  2. if(this.getInterceptors() != null) {

  3. for(int i = 0; i < this.getInterceptors().length; this.interceptorIndex = i++) {

  4. HandlerInterceptor interceptor = this.getInterceptors()[i];

  5. if(!interceptor.preHandle(request, response, this.handler)) {

  6. this.triggerAfterCompletion(request, response, (Exception)null);

  7. return false;

  8. }

  9. }

  10. }

  11.  
  12. return true;

  13. }

可以看到这里是在循环着执行执行链中放入的需要执行的拦截器的preHandle方法(正叙执行)。如果碰到一个拦截器返回为false,则直接执行triggerAfterCompletion,

应该都还记得拦截器有三个方法,preHandle  postHandle  afterCompletion  然而,这个方法就执行,afterCompletion  。反正也没事再进去瞄瞄怎么执行。

 
  1. void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception {

  2. if(this.getInterceptors() != null) {

  3. for(int i = this.interceptorIndex; i >= 0; --i) {

  4. HandlerInterceptor interceptor = this.getInterceptors()[i];

  5.  
  6. try {

  7. interceptor.afterCompletion(request, response, this.handler, ex);

  8. } catch (Throwable var7) {

  9. logger.error("HandlerInterceptor.afterCompletion threw exception", var7);

  10. }

  11. }

  12.  
  13. }

  14. }

可以看到确实在执行着拦截器的afterCompletion  方法,但是这里面的循环不再是正叙,而是倒叙,这也就是为什么前一篇博客得出的结论,afterCompletion  为倒叙执行。

看到下面这张图的执行结果就恍然大悟了。

前端控制器执行handler之前,执行拦截器操作到此执行完毕。然后才是真正的执行handler。

接下来看下面这块代码

err = ex.handle(processedRequest, response, mappedHandler.getHandler());

看看它的源码,源码在 AbstractHandlerMethodAdapter.java中。

 
  1. public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

  2. return this.handleInternal(request, response, (HandlerMethod)handler);

  3. }

继续跟进,发现真正的源码在,RequestMappingHandlerAdapter.java的handleInternal方法里面

 
  1. protected final ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

  2. if(this.getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {

  3. this.checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);

  4. } else {

  5. this.checkAndPrepare(request, response, true);

  6. }

  7.  
  8. if(this.synchronizeOnSession) {

  9. HttpSession session = request.getSession(false);

  10. if(session != null) {

  11. Object mutex = WebUtils.getSessionMutex(session);

  12. synchronized(mutex) {

  13. return this.invokeHandleMethod(request, response, handlerMethod);

  14. }

  15. }

  16. }

  17.  
  18. return this.invokeHandleMethod(request, response, handlerMethod);

  19. }

invokeHandleMethod看着很眼熟,java反射机制里面执行某个方法用的就是invoke。

跟进去看看

 
  1. private ModelAndView invokeHandleMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

  2. ServletWebRequest webRequest = new ServletWebRequest(request, response);

  3. WebDataBinderFactory binderFactory = this.getDataBinderFactory(handlerMethod);

  4. ModelFactory modelFactory = this.getModelFactory(handlerMethod, binderFactory);

  5. ServletInvocableHandlerMethod requestMappingMethod = this.createRequestMappingMethod(handlerMethod, binderFactory);

  6. ModelAndViewContainer mavContainer = new ModelAndViewContainer();

  7. mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));

  8. modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);

  9. mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

  10. AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);

  11. asyncWebRequest.setTimeout(this.asyncRequestTimeout);

  12. WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

  13. asyncManager.setTaskExecutor(this.taskExecutor);

  14. asyncManager.setAsyncWebRequest(asyncWebRequest);

  15. asyncManager.registerCallableInterceptors(this.callableInterceptors);

  16. asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

  17. if(asyncManager.hasConcurrentResult()) {

  18. Object result = asyncManager.getConcurrentResult();

  19. mavContainer = (ModelAndViewContainer)asyncManager.getConcurrentResultContext()[0];

  20. asyncManager.clearConcurrentResult();

  21. if(this.logger.isDebugEnabled()) {

  22. this.logger.debug("Found concurrent result value [" + result + "]");

  23. }

  24.  
  25. requestMappingMethod = requestMappingMethod.wrapConcurrentResult(result);

  26. }

  27.  
  28. requestMappingMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);

  29. return asyncManager.isConcurrentHandlingStarted()?null:this.getModelAndView(mavContainer, modelFactory, webRequest);

  30. }

可以看到在执行之前做了一堆的事前准备工作。其他的可以不用理会,主要看
requestMappingMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);做了一些什么事情。
 

 
  1. public final void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {

  2. Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);

  3. this.setResponseStatus(webRequest);

  4. if(returnValue == null) {

  5. if(this.isRequestNotModified(webRequest) || this.hasResponseStatus() || mavContainer.isRequestHandled()) {

  6. mavContainer.setRequestHandled(true);

  7. return;

  8. }

  9. } else if(StringUtils.hasText(this.responseReason)) {

  10. mavContainer.setRequestHandled(true);

  11. return;

  12. }

  13.  
  14. mavContainer.setRequestHandled(false);

  15.  
  16. try {

  17. this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);

  18. } catch (Exception var6) {

  19. if(this.logger.isTraceEnabled()) {

  20. this.logger.trace(this.getReturnValueHandlingErrorMessage("Error handling return value", returnValue), var6);

  21. }

  22.  
  23. throw var6;

  24. }

  25. }

代码中大部分还是在校验,设值,只有invokeForRequest它在干着实事。再看看。它在 InvocableHandlerMethod.java 中

 
  1. public final Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {

  2. Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);

  3. if(this.logger.isTraceEnabled()) {

  4. StringBuilder returnValue = new StringBuilder("Invoking [");

  5. returnValue.append(this.getBeanType().getSimpleName()).append(".");

  6. returnValue.append(this.getMethod().getName()).append("] method with arguments ");

  7. returnValue.append(Arrays.asList(args));

  8. this.logger.trace(returnValue.toString());

  9. }

  10.  
  11. Object returnValue1 = this.invoke(args);

  12. if(this.logger.isTraceEnabled()) {

  13. this.logger.trace("Method [" + this.getMethod().getName() + "] returned [" + returnValue1 + "]");

  14. }

  15.  
  16. return returnValue1;

  17. }

终于找到了,Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);这句在给需要执行的handler的方法准备参数信息。然后

Object returnValue1 = this.invoke(args);来执行方法。 

总算找到了,曲曲折折饶了一大弯。最后返回一个ModelAndView给前端控制器。

然后开始执行拦截器的postHandle   也就是这句---- mappedHandler.applyPostHandle(processedRequest, response, err);

源码

 
  1. void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {

  2. if(this.getInterceptors() != null) {

  3. for(int i = this.getInterceptors().length - 1; i >= 0; --i) {

  4. HandlerInterceptor interceptor = this.getInterceptors()[i];

  5. interceptor.postHandle(request, response, this.handler, mv);

  6. }

  7.  
  8. }

  9. }

看的出来跟   triggerAfterCompletion   的执行有相似之处,都是倒叙执行。

所以拦截器那篇博客的结论,所有的preHandle方法都为true的时候postHandle才执行,并且是倒叙执行。这就是原因,这就是原理。

最后前端控制器 开始请求视图解析器解析视图,渲染视图等等

this.processDispatchResult(processedRequest, response, mappedHandler, err, dispatchException);

 
  1. private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {

  2. boolean errorView = false;

  3. if(exception != null) {

  4. if(exception instanceof ModelAndViewDefiningException) {

  5. this.logger.debug("ModelAndViewDefiningException encountered", exception);

  6. mv = ((ModelAndViewDefiningException)exception).getModelAndView();

  7. } else {

  8. Object handler = mappedHandler != null?mappedHandler.getHandler():null;

  9. mv = this.processHandlerException(request, response, handler, exception);

  10. errorView = mv != null;

  11. }

  12. }

  13.  
  14. if(mv != null && !mv.wasCleared()) {

  15. this.render(mv, request, response);

  16. if(errorView) {

  17. WebUtils.clearErrorRequestAttributes(request);

  18. }

  19. } else if(this.logger.isDebugEnabled()) {

  20. this.logger.debug("Null ModelAndView returned to DispatcherServlet with name \'" + this.getServletName() + "\': assuming HandlerAdapter completed request handling");

  21. }

  22.  
  23. if(!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {

  24. if(mappedHandler != null) {

  25. mappedHandler.triggerAfterCompletion(request, response, (Exception)null);

  26. }

  27.  
  28. }

  29. }

这里的代码分三块,一块看看执行Handler结果有没有异常,有的话处理异常,注意这里可以自定义异常,来统一处理。

另一块就是说的请求视图解析器解析,渲染视图等操作。

最后又看到了眼熟的   triggerAfterCompletion  了,这里不在看它。

主要看  this.render(mv, request, response);  看它是怎么请求视图解析器,渲染视图的。

 
  1. protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {

  2. Locale locale = this.localeResolver.resolveLocale(request);

  3. response.setLocale(locale);

  4. View view;

  5. if(mv.isReference()) {

  6. view = this.resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);

  7. if(view == null) {

  8. throw new ServletException("Could not resolve view with name \'" + mv.getViewName() + "\' in servlet with name \'" + this.getServletName() + "\'");

  9. }

  10. } else {

  11. view = mv.getView();

  12. if(view == null) {

  13. throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " + "View object in servlet with name \'" + this.getServletName() + "\'");

  14. }

  15. }

  16.  
  17. if(this.logger.isDebugEnabled()) {

  18. this.logger.debug("Rendering view [" + view + "] in DispatcherServlet with name \'" + this.getServletName() + "\'");

  19. }

  20.  
  21. try {

  22. view.render(mv.getModelInternal(), request, response);

  23. } catch (Exception var7) {

  24. if(this.logger.isDebugEnabled()) {

  25. this.logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name \'" + this.getServletName() + "\'", var7);

  26. }

  27.  
  28. throw var7;

  29. }

  30. }

这里面,前一个if else就是在请求视图解析器。可以看看resolveViewName方法是怎么通过解析器获得视图view的。

 
  1. protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception {

  2. Iterator var5 = this.viewResolvers.iterator();

  3.  
  4. View view;

  5. do {

  6. if(!var5.hasNext()) {

  7. return null;

  8. }

  9.  
  10. ViewResolver viewResolver = (ViewResolver)var5.next();

  11. view = viewResolver.resolveViewName(viewName, locale);

  12. } while(view == null);

  13.  
  14. return view;

  15. }

看看即可,不是设么高深的代码。

获取到view以后  开始对视图进行渲染,也就是将模型中的数据填充到request中去,

进入到  AbstractView.java 中

 
  1. public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {

  2. if(this.logger.isTraceEnabled()) {

  3. this.logger.trace("Rendering view with name \'" + this.beanName + "\' with model " + model + " and static attributes " + this.staticAttributes);

  4. }

  5.  
  6. Map mergedModel = this.createMergedOutputModel(model, request, response);

  7. this.prepareResponse(request, response);

  8. this.renderMergedOutputModel(mergedModel, request, response);

  9. }

没什么好看的,继续跟踪,renderMergedOutputModel方法。

    protected abstract void renderMergedOutputModel(Map<String, Object> var1, HttpServletRequest var2, HttpServletResponse var3) throws Exception;

发现是个抽象方法,记得springmvc.xml中配置的视图解析器是   InternalResourceViewResolver  所以它对应的 View 是 InternalResourceView

所以会调到这个类里面的renderMergedOutpitModel方法中,上代码

 
  1. protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {

  2. HttpServletRequest requestToExpose = this.getRequestToExpose(request);

  3. this.exposeModelAsRequestAttributes(model, requestToExpose);

  4. this.exposeHelpers(requestToExpose);

  5. String dispatcherPath = this.prepareForRendering(requestToExpose, response);

  6. RequestDispatcher rd = this.getRequestDispatcher(requestToExpose, dispatcherPath);

  7. if(rd == null) {

  8. throw new ServletException("Could not get RequestDispatcher for [" + this.getUrl() + "]: Check that the corresponding file exists within your web application archive!");

  9. } else {

  10. if(this.useInclude(requestToExpose, response)) {

  11. response.setContentType(this.getContentType());

  12. if(this.logger.isDebugEnabled()) {

  13. this.logger.debug("Including resource [" + this.getUrl() + "] in InternalResourceView \'" + this.getBeanName() + "\'");

  14. }

  15.  
  16. rd.include(requestToExpose, response);

  17. } else {

  18. if(this.logger.isDebugEnabled()) {

  19. this.logger.debug("Forwarding to resource [" + this.getUrl() + "] in InternalResourceView \'" + this.getBeanName() + "\'");

  20. }

  21.  
  22. rd.forward(requestToExpose, response);

  23. }

  24.  
  25. }

  26. }

先来看看里面的exposeModelAsRequestAttributes方法

 
  1. protected void exposeModelAsRequestAttributes(Map<String, Object> model, HttpServletRequest request) throws Exception {

  2. Iterator var3 = model.entrySet().iterator();

  3.  
  4. while(var3.hasNext()) {

  5. Entry entry = (Entry)var3.next();

  6. String modelName = (String)entry.getKey();

  7. Object modelValue = entry.getValue();

  8. if(modelValue != null) {

  9. request.setAttribute(modelName, modelValue);

  10. if(this.logger.isDebugEnabled()) {

  11. this.logger.debug("Added model object \'" + modelName + "\' of type [" + modelValue.getClass().getName() + "] to request in view with name \'" + this.getBeanName() + "\'");

  12. }

  13. } else {

  14. request.removeAttribute(modelName);

  15. if(this.logger.isDebugEnabled()) {

  16. this.logger.debug("Removed model object \'" + modelName + "\' from request in view with name \'" + this.getBeanName() + "\'");

  17. }

  18. }

  19. }

  20.  
  21. }

前面说的什么渲染视图,将模型中的数据填充到request中去,就是这里实现了,前面的ModelAndView中的模型数据都已经放入到这个传入的map中去了,然后什么报文头等等页面需要的,最后统一放入到request中去。

看完了   exposeModelAsRequestAttributes  再看 接下来的代码,
this.exposeHelpers(requestToExpose);对应的是空代码块,不在说了。

String dispatcherPath = this.prepareForRendering(requestToExpose, response);  // 得到view所在的路径  Dispatcher要跳转的路径
RequestDispatcher rd = this.getRequestDispatcher(requestToExpose, dispatcherPath);  得到一个Dispatcher

 
  1. if(this.useInclude(requestToExpose, response)) {

  2. response.setContentType(this.getContentType());

  3. if(this.logger.isDebugEnabled()) {

  4. this.logger.debug("Including resource [" + this.getUrl() + "] in InternalResourceView \'" + this.getBeanName() + "\'");

  5. }

  6.  
  7. rd.include(requestToExpose, response);

  8. } else {

  9. if(this.logger.isDebugEnabled()) {

  10. this.logger.debug("Forwarding to resource [" + this.getUrl() + "] in InternalResourceView \'" + this.getBeanName() + "\'");

  11. }

  12.  
  13. rd.forward(requestToExpose, response);

  14. }

这里设置跳转的路径,这个include和forword的具体区别,请看

http://blog.csdn.net/huo2007201019/article/details/7584241

这里执行完毕后,就要执行拦截器的最后操作,以及一些final里面的内容。

流程方面的源码解析,完毕。

猜你喜欢

转载自blog.csdn.net/Lecter_13/article/details/81567176
今日推荐