整个spring mvc的架构如下图所示:

上篇文件讲解了DispatcherServlet通过request获取控制器Controller的过程,现在来讲解DispatcherServletDispatcherServlet的第二步:通过request从Controller获取ModelAndView。

DispatcherServlet调用Controller的过程:

DispatcherServlet.java

doService()--->doDispatch()--->handlerAdapter的handle()方法

  1. try {// Actually invoke the handler.
  2. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
  3. }
  4. finally {
  5. if (asyncManager.isConcurrentHandlingStarted()) {
  6. return;
  7. }
  8. }

最常用的实现了HandlerAdapter接口是SimpleControllerHandlerAdapter类,该类将

  1. 两个不兼容的类:DispatcherServlet Controller 类连接到一起。
  1. Adapter to use the plain {@link Controller} workflow interface with
  2. the generic {@link org.springframework.web.servlet.DispatcherServlet}.
  3. Supports handlers that implement the {@link LastModified} interface.
  4.  
  5. <p>This is an SPI class, not used directly by application code.

类之间的转换代码如下所示,调用了Controller类的handleRequest()方法来处理请求:

  1. @Override
  2. public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
  3. throws Exception {
  4.  
  5. return ((Controller) handler).handleRequest(request, response);
  6. }

重量级人物控制器Controller开始闪亮登场,Controller是一个基本的接口,它接受request和response,从这点上来说,它有点像servlet,但不同之处在于它在mvc模式流程中起作用,它和struts中的Action作用类似。继承该接口的控制器或者类应该保证是线程安全的,可复用的,能够在一个应用生命周期中处理大量的request。为了使Controller的配置更便捷,通常使用javaBeans来继承Controller。

  1. /**
  2. * Base Controller interface, representing a component that receives
  3. * {@code HttpServletRequest} and {@code HttpServletResponse}
  4. * instances just like a {@code HttpServlet} but is able to
  5. * participate in an MVC workflow. Controllers are comparable to the
  6. * notion of a Struts {@code Action}.
  7. *
  8. * <p>Any implementation of the Controller interface should be a
  9. * <i>reusable, thread-safe</i> class, capable of handling multiple
  10. * HTTP requests throughout the lifecycle of an application. To be able to
  11. * configure a Controller easily, Controller implementations are encouraged
  12. * to be (and usually are) JavaBeans.
  13. * </p>
  14. *
  15. * <p><b><a name="workflow">Workflow</a></b></p>
  16. *
  17. * <p>
  18. * After a <cde>DispatcherServlet</code> has received a request and has
  19. * done its work to resolve locales, themes and suchlike, it then tries
  20. * to resolve a Controller, using a
  21. * {@link org.springframework.web.servlet.HandlerMapping HandlerMapping}.
  22. * When a Controller has been found to handle the request, the
  23. * {@link #handleRequest(HttpServletRequest, HttpServletResponse) handleRequest}
  24. * method of the located Controller will be invoked; the located Controller
  25. * is then responsible for handling the actual request and - if applicable -
  26. * returning an appropriate
  27. * {@link org.springframework.web.servlet.ModelAndView ModelAndView}.
  28. * So actually, this method is the main entrypoint for the
  29. * {@link org.springframework.web.servlet.DispatcherServlet DispatcherServlet}
  30. * which delegates requests to controllers.</p>
  31. *
  32. * <p>So basically any <i>direct</i> implementation of the Controller interface
  33. * just handles HttpServletRequests and should return a ModelAndView, to be further
  34. * interpreted by the DispatcherServlet. Any additional functionality such as
  35. * optional validation, form handling, etc should be obtained through extending
  36. * one of the abstract controller classes mentioned above.</p>
  37. *
  38. * <p><b>Notes on design and testing</b></p>
  39. *
  40. * <p>The Controller interface is explicitly designed to operate on HttpServletRequest
  41. * and HttpServletResponse objects, just like an HttpServlet. It does not aim to
  42. * decouple itself from the Servlet API, in contrast to, for example, WebWork, JSF or Tapestry.
  43. * Instead, the full power of the Servlet API is available, allowing Controllers to be
  44. * general-purpose: a Controller is able to not only handle web user interface
  45. * requests but also to process remoting protocols or to generate reports on demand.</p>
  46. *
  47. * <p>Controllers can easily be tested by passing in mock objects for the
  48. * HttpServletRequest and HttpServletResponse objects as parameters to the
  49. * {@link #handleRequest(HttpServletRequest, HttpServletResponse) handleRequest}
  50. * method. As a convenience, Spring ships with a set of Servlet API mocks
  51. * that are suitable for testing any kind of web components, but are particularly
  52. * suitable for testing Spring web controllers. In contrast to a Struts Action,
  53. * there is no need to mock the ActionServlet or any other infrastructure;
  54. * HttpServletRequest and HttpServletResponse are sufficient.</p>
  55. *
  56. * <p>If Controllers need to be aware of specific environment references, they can
  57. * choose to implement specific awareness interfaces, just like any other bean in a
  58. * Spring (web) application context can do, for example:</p>
  59. * <ul>
  60. * <li>{@code org.springframework.context.ApplicationContextAware}</li>
  61. * <li>{@code org.springframework.context.ResourceLoaderAware}</li>
  62. * <li>{@code org.springframework.web.context.ServletContextAware}</li>
  63. * </ul>
  64. *
  65. * <p>Such environment references can easily be passed in testing environments,
  66. * through the corresponding setters defined in the respective awareness interfaces.
  67. * In general, it is recommended to keep the dependencies as minimal as possible:
  68. * for example, if all you need is resource loading, implement ResourceLoaderAware only.
  69. * Alternatively, derive from the WebApplicationObjectSupport base class, which gives
  70. * you all those references through convenient accessors - but requires an
  71. * ApplicationContext reference on initialization.
  72. *
  73. * <p>Controllers can optionally implement the {@link LastModified} interface.
    */

Controller的handleRequest()方法处理请求,并返回ModelAndView给DispatcherServlet去渲染render。

Controller接口的抽象实现类为:AbstractController,它通过互斥锁(mutex)来保证线程安全。

  1. /**
  2. * Set if controller execution should be synchronized on the session,
  3. * to serialize parallel invocations from the same client.
  4. * <p>More specifically, the execution of the {@code handleRequestInternal}
  5. * method will get synchronized if this flag is "true". The best available
  6. * session mutex will be used for the synchronization; ideally, this will
  7. * be a mutex exposed by HttpSessionMutexListener.
  8. * <p>The session mutex is guaranteed to be the same object during
  9. * the entire lifetime of the session, available under the key defined
  10. * by the {@code SESSION_MUTEX_ATTRIBUTE} constant. It serves as a
  11. * safe reference to synchronize on for locking on the current session.
  12. * <p>In many cases, the HttpSession reference itself is a safe mutex
  13. * as well, since it will always be the same object reference for the
  14. * same active logical session. However, this is not guaranteed across
  15. * different servlet containers; the only 100% safe way is a session mutex.
  16. * @see AbstractController#handleRequestInternal
  17. * @see org.springframework.web.util.HttpSessionMutexListener
  18. * @see org.springframework.web.util.WebUtils#getSessionMutex(javax.servlet.http.HttpSession)
  19. */

线程安全实现:

  1. public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
  2. throws Exception {
  3.  
  4. // Delegate to WebContentGenerator for checking and preparing.
  5. checkAndPrepare(request, response, this instanceof LastModified);
  6.  
  7. // Execute handleRequestInternal in synchronized block if required.
  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 handleRequestInternal(request, response);
  14. }
  15. }
  16. }
  17.  
  18. return handleRequestInternal(request, response);
  19. }
  1. handleRequestInternal()为抽象方法,留待具体实现类来实现。它的直接子类有:
  1. 简单Controller实现
    web.xml中有时候定义节点<welcome-list>index.html</welcome-list>等,这种简单的请,Controller是如何实现的呢?我们来看看UrlFilenameViewController,它是Controller的一个间接实现,实现了AbstractUrlViewController。它把url的虚拟路径转换成一个view的名字,然后返回这个view
  1. protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) {
  2. String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
  3. String viewName = getViewNameForRequest(request);
  4. if (logger.isDebugEnabled()) {
  5. logger.debug("Returning view name '" + viewName + "' for lookup path [" + lookupPath + "]");
  6. }
  7. return new ModelAndView(viewName, RequestContextUtils.getInputFlashMap(request));
  8. }

复杂Controller实现

一个可以处理多种请求类型的Controller实现:MultiActionController。它类似于struts中的DispatcherAction,但更灵活,而且支持代理。

  1. /**
  2. * {@link org.springframework.web.servlet.mvc.Controller Controller}
  3. * implementation that allows multiple request types to be handled by the same
  4. * class. Subclasses of this class can handle several different types of
  5. * request with methods of the form
  6. *
  7. * <pre class="code">public (ModelAndView | Map | String | void) actionName(HttpServletRequest request, HttpServletResponse response, [,HttpSession] [,AnyObject]);</pre>
  8. *
  9. * A Map return value indicates a model that is supposed to be passed to a default view
  10. * (determined through a {@link org.springframework.web.servlet.RequestToViewNameTranslator}).
  11. * A String return value indicates the name of a view to be rendered without a specific model.
  12. *
  13. * <p>May take a third parameter (of type {@link HttpSession}) in which an
  14. * existing session will be required, or a third parameter of an arbitrary
  15. * class that gets treated as the command (that is, an instance of the class
  16. * gets created, and request parameters get bound to it)
  17. *
  18. * <p>These methods can throw any kind of exception, but should only let
  19. * propagate those that they consider fatal, or which their class or superclass
  20. * is prepared to catch by implementing an exception handler.
  21. *
  22. * <p>When returning just a {@link Map} instance view name translation will be
  23. * used to generate the view name. The configured
  24. * {@link org.springframework.web.servlet.RequestToViewNameTranslator} will be
  25. * used to determine the view name.
  26. *
  27. * <p>When returning {@code void} a return value of {@code null} is
  28. * assumed meaning that the handler method is responsible for writing the
  29. * response directly to the supplied {@link HttpServletResponse}.
  30. *
  31. * <p>This model allows for rapid coding, but loses the advantage of
  32. * compile-time checking. It is similar to a Struts {@code DispatchAction},
  33. * but more sophisticated. Also supports delegation to another object.
  34. *
  35. * <p>An implementation of the {@link MethodNameResolver} interface defined in
  36. * this package should return a method name for a given request, based on any
  37. * aspect of the request, such as its URL or an "action" parameter. The actual
  38. * strategy can be configured via the "methodNameResolver" bean property, for
  39. * each {@code MultiActionController}.
  40. *
  41. * <p>The default {@code MethodNameResolver} is
  42. * {@link InternalPathMethodNameResolver}; further included strategies are
  43. * {@link PropertiesMethodNameResolver} and {@link ParameterMethodNameResolver}.
  44. *
  45. * <p>Subclasses can implement custom exception handler methods with names such
  46. * as:
  47. *
  48. * <pre class="code">public ModelAndView anyMeaningfulName(HttpServletRequest request, HttpServletResponse response, ExceptionClass exception);</pre>
  49. *
  50. * The third parameter can be any subclass or {@link Exception} or
  51. * {@link RuntimeException}.
  52. *
  53. * <p>There can also be an optional {@code xxxLastModified} method for
  54. * handlers, of signature:
  55. *
  56. * <pre class="code">public long anyMeaningfulNameLastModified(HttpServletRequest request)</pre>
  57. *
  58. * If such a method is present, it will be invoked. Default return from
  59. * {@code getLastModified} is -1, meaning that the content must always be
  60. * regenerated.
  61. *
  62. * <p><b>Note that all handler methods need to be public and that
  63. * method overloading is <i>not</i> allowed.</b>
  64. *
  65. * <p>See also the description of the workflow performed by
  66. * {@link AbstractController the superclass} (in that section of the class
  67. * level Javadoc entitled 'workflow').
  68. *
  69. * <p><b>Note:</b> For maximum data binding flexibility, consider direct usage of a
  70. * {@link ServletRequestDataBinder} in your controller method, instead of relying
  71. * on a declared command argument. This allows for full control over the entire
  72. * binder setup and usage, including the invocation of {@link Validator Validators}
  73. * and the subsequent evaluation of binding/validation errors.*/

根据方法名决定处理的handler

  1. protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
  2. throws Exception {
  3. try {
  4. String methodName = this.methodNameResolver.getHandlerMethodName(request);
  5. return invokeNamedMethod(methodName, request, response);
  6. }
  7. catch (NoSuchRequestHandlingMethodException ex) {
  8. return handleNoSuchRequestHandlingMethod(ex, request, response);
  9. }
  10. }

触发执行方法:

  1. protected final ModelAndView invokeNamedMethod(
  2. String methodName, HttpServletRequest request, HttpServletResponse response) throws Exception {
  3.  
  4. Method method = this.handlerMethodMap.get(methodName);
  5. if (method == null) {
  6. throw new NoSuchRequestHandlingMethodException(methodName, getClass());
  7. }
  8.  
  9. try {
  10. Class<?>[] paramTypes = method.getParameterTypes();
  11. List<Object> params = new ArrayList<Object>(4);
  12. params.add(request);
  13. params.add(response);
  14.  
  15. if (paramTypes.length >= 3 && paramTypes[2].equals(HttpSession.class)) {
  16. HttpSession session = request.getSession(false);
  17. if (session == null) {
  18. throw new HttpSessionRequiredException(
  19. "Pre-existing session required for handler method '" + methodName + "'");
  20. }
  21. params.add(session);
  22. }
  23.  
  24. // If last parameter isn't of HttpSession type, it's a command.
  25. if (paramTypes.length >= 3 &&
  26. !paramTypes[paramTypes.length - 1].equals(HttpSession.class)) {
  27. Object command = newCommandObject(paramTypes[paramTypes.length - 1]);
  28. params.add(command);
  29. bind(request, command);
  30. }
  31.  
  32. Object returnValue = method.invoke(this.delegate, params.toArray(new Object[params.size()]));
  33. return massageReturnValueIfNecessary(returnValue);
  34. }
  35. catch (InvocationTargetException ex) {
  36. // The handler method threw an exception.
  37. return handleException(request, response, ex.getTargetException());
  38. }
  39. catch (Exception ex) {
  40. // The binding process threw an exception.
  41. return handleException(request, response, ex);
  42. }

处理返回结果,要么返回null要么返回ModelAndView实例。当返回一个Map类型时,ModelAndView实例包装的Map类型。

  1. /**
  2. * Processes the return value of a handler method to ensure that it either returns
  3. * {@code null} or an instance of {@link ModelAndView}. When returning a {@link Map},
  4. * the {@link Map} instance is wrapped in a new {@link ModelAndView} instance.
  5. */
  6. @SuppressWarnings("unchecked")
  7. private ModelAndView massageReturnValueIfNecessary(Object returnValue) {
  8. if (returnValue instanceof ModelAndView) {
  9. return (ModelAndView) returnValue;
  10. }
  11. else if (returnValue instanceof Map) {
  12. return new ModelAndView().addAllObjects((Map<String, ?>) returnValue);
  13. }
  14. else if (returnValue instanceof String) {
  15. return new ModelAndView((String) returnValue);
  16. }
  17. else {
  18. // Either returned null or was 'void' return.
  19. // We'll assume that the handle method already wrote the response.
  20. return null;
  21. }
  22. }

小结:

DispatcherServlet接受一个请求,然后解析完locales, themes等后,通过HadlerMapping解析控制器Controller去处理请求。

找到Controller后,出发当前controller的handleRequest()方法,此controller负责真正处理请求,然后一个ModelAndView实例。

DispatcherServlet 代理此Controller,接收返回结果,然后进行渲染。

  1.  

spring mvc DispatcherServlet详解之二---request通过Controller获取ModelAndView过程的更多相关文章

  1. spring mvc DispatcherServlet详解之三---request通过ModelAndView中获取View实例的过程

    整个spring mvc的架构如下图所示: 上篇文件讲解了DispatcherServlet第二步:通过request从Controller获取ModelAndView.现在来讲解第三步:reques ...

  2. spring mvc DispatcherServlet详解之一--request通过HandlerMaping获取控制器Controller过程

    整个spring mvc的架构如下图所示: 现在来讲解DispatcherServletDispatcherServlet的第一步:获取控制器. HandlerMapping HandlerMappi ...

  3. spring mvc DispatcherServlet详解之前传---FrameworkServlet

    做项目时碰到Controller不能使用aop进行拦截,从网上搜索得知:使用spring mvc 启动了两个context:applicationContext 和WebapplicationCont ...

  4. (转载)spring mvc DispatcherServlet详解之一---处理请求深入解析

    要深入理解spring mvc的工作流程,就需要先了解spring mvc的架构: 从上图可以看到 前端控制器DispatcherServlet在其中起着主导作用,理解了DispatcherServl ...

  5. spring mvc DispatcherServlet详解之四---视图渲染过程

    整个spring mvc的架构如下图所示: 现在来讲解DispatcherServletDispatcherServlet的最后一步:视图渲染.视图渲染的过程是在获取到ModelAndView后的过程 ...

  6. spring mvc DispatcherServlet详解之interceptor和filter的区别

    首先我们看一下spring mvc Interceptor的功能及实现: http://wenku.baidu.com/link?url=Mw3GaUhCRMhUFjU8iIDhObQpDcbmmRy ...

  7. spring mvc DispatcherServlet详解之一---处理请求深入解析

    要深入理解spring mvc的工作流程,就需要先了解spring mvc的架构: 从上图可以看到 前端控制器DispatcherServlet在其中起着主导作用,理解了DispatcherServl ...

  8. spring mvc DispatcherServlet详解之前传---前端控制器架构

    前端控制器是整个MVC框架中最为核心的一块,它主要用来拦截符合要求的外部请求,并把请求分发到不同的控制器去处理,根据控制器处理后的结果,生成相应的响应发送到客户端.前端控制器既可以使用Filter实现 ...

  9. spring mvc DispatcherServlet详解前传---HttpServletBean类

    从上章里我们已经看到: DispatcherServlet extends FrameworkServlet FrameworkServlet extends HttpServletBean impl ...

随机推荐

  1. POJ 2513 Colored Sticks 字典树、并查集、欧拉通路

    Description You are given a bunch of wooden sticks. Each endpoint of each stick is colored with some ...

  2. require.js 入门学习-备

    一.为什么要用require.js? 最早的时候,所有Javascript代码都写在一个文件里面,只要加载这一个文件就够了.后来,代码越来越多,一个文件不够了,必须分成多个文件,依次加载.下面的网页代 ...

  3. VS中无法加入断点进行调试解决方案

    原文地址:http://blog.csdn.net/gukesdo/article/details/6535054 [ 1] 以前也遇到过同样的问题,但没有问个为什么,也没有探个毕竟.昨天调试一个DL ...

  4. NOR FLASH与NAND FLASH

    整理自NOR FLASH 与NAND FLASH 1:NandFlash与NorFlash典型电路图 Nor Flash接原理图 从上图可以看出,该NorFlash采用并行地址和数据总线, 其中,21 ...

  5. python处理LINUX的PWD文档

    用冒号分隔的哟. 此章后面讲的JSON,配置文件读取,原理应该一样吧,只是要用合适的包去处理吧. CSV文档是用CSV包处理的. 文档: root:x:0:0:root:/root:/bin/bash ...

  6. LeetCode解题报告:LRU Cache

    LRU Cache Design and implement a data structure for Least Recently Used (LRU) cache. It should suppo ...

  7. 短信验证码js实现

    短信验证码实现 我们在使用移动.电信等运营商网上营业厅的时候,为确保业务的完整和正确性,经常会需要用到短信的验证码.最近因为某省业务需要,也做了个类似的功能. 原理很简单,就是在用户点击"获 ...

  8. bzoj2131

    首先不难想到对t排序,有f[i]=max(f[j])+v[i] tj<=ti且abs(pi-pj)/2<=ti-tj;要想优化,肯定从优化转移入手先去绝对值,当pi>=pj时,可得2 ...

  9. 每天一个linux命令:mkdir

    linux mkdir 命令用来创建指定的名称的目录,要求创建目录的用户在当前目录中具有写权限,并且指定的目录名不能是当前目录中已有的目录. 1.命令格式: mkdir [选项] 目录... 2.命令 ...

  10. Android 布局之DrawLayout

    在刚开始学android的时候肯定会知道,android的主要的布局就是LinearLayout.RelativeLayout.FramLayout.AbsoluteLayout.以及TableLay ...