Spring MVC架构浅析
阅读目录
- Spring MVC概述
- Spring MVC框架的特点
- Spring MVC工作原理
Spring MVC概述
Spring的web框架围绕DispatcherServlet
设计,DispatcherServlet
的作用是将请求分发到不同的处理器。
Spring的web框架包括可配置的处理器(handler)映射、视图(view)解析、本地化(local)解析、 主题(theme)解析以及对文件上传的支持。
Spring的Web框架中缺省的处理器是org.springframework.web.servlet.mvc.Controller
接口
public interface Controller { /** * Process the request and return a ModelAndView object which the DispatcherServlet * will render. A {@code null} return value is not an error: it indicates that * this object completed request processing itself and that there is therefore no * ModelAndView to render. * @param request current HTTP request * @param response current HTTP response * @return a ModelAndView to render, or {@code null} if handled directly * @throws Exception in case of errors */ ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception; }
可以通过实现这个接口来创建自己的控制器(也可以称之为处理器),但是更推荐继承Spring提供的一系列控制器, 比如AbstractController
、AbstractCommandController
和SimpleFormController
。
注意,需要选择正确的基类:如果没有表单,就不需要一个FormController, 这是和Struts的一个主要区别。
Spring Web MVC允许使用任何对象作为命令对象(或表单对象),不必实现某个特定于框架的接口或从某个基类继承。
Spring的数据绑定相当灵活,例如,它认为类型不匹配这样的错误应该是应用级的验证错误,而不是系统错误,所以你不需要为了保证表单内容的正确提交,而重复定义一个和业务对象有相同属性的表单对象来处理简单的无类型字符串或者对字符串进行转换。这也是和Struts相比的另一个重要区别,Struts是围绕 Action和ActionForm等基类构建的。和WebWork相比,Spring将对象细分成更多不同的角色:控制器( Controller
)、可选的命令对象(Command Object)或表单对象(Form Object), 以及传递到视图的模型(Model)。
模型不仅包含命令对象或表单对象,而且也可以包含任何引用数据。 相比之下,WebWork的Action
将所有的这些角色都合并在一个单独的对象里。 虽然WebWork的确允许在表单中使用现有的业务对象,但是必须把它们定义成相应的Action
类的bean属性。
更重要的是,在进行视图层(View)运算和表单赋值时,WebWork使用的是同一个处理请求的 Action
实例。因此,引用数据也需要被定义成Action
的bean属性。这样一个对象就承担了太多的角色(当然,对于这个观点仍有争议)。
Spring的视图解析相当灵活。一个控制器甚至可以直接向response输出一个视图 (此时控制器返回ModelAndView的值必须是null)。
在一般的情况下,一个ModelAndView 实例包含一个视图名字和一个类型为Map
的model, 一个model是一些以bean的名字为key,以bean对象(可以是命令或form,也可以是其他的JavaBean) 为value的键值对。
对视图名称的解析处理也是高度可配置的,可以通过bean的名字、属性文件或者自定义的 ViewResolver
实现来进行解析。
实际上基于 Map
的model(也就是MVC中的M)是高度抽象的,适用于各种表现层技术。 也就是说,任何表现层都可以直接和Spring集成,无论是JSP、Velocity还是其它表现层技术。
Map model可以被转换成合适的格式,比如JSP request attribute或者Velocity template model。
Spring MVC框架的特点
-
清晰的角色划分:控制器(controller)、验证器(validator)、 命令对象(command object)、表单对象(form object)、模型对象(model object)、 Servlet分发器(
DispatcherServlet
)、 处理器映射(handler mapping)、视图解析器(view resolver)等等。 每一个角色都可以由一个专门的对象来实现。 -
强大而直接的配置方式:将框架类和应用程序类都能作为JavaBean配置,支持跨多个context的引用,例如,在web控制器中对业务对象和验证器(validator)的引用。
-
可适配、非侵入:可以根据不同的应用场景,选择合适的控制器子类 (simple型、command型、form型、wizard型、multi-action型或者自定义),而不是从单一控制器 (比如Action/ActionForm)继承。
-
可重用的业务代码:可以使用现有的业务对象作为命令或表单对象,而不需要去扩展某个特定框架的基类。
-
可定制的绑定(binding) 和验证(validation):比如将类型不匹配作为应用级的验证错误, 这可以保存错误的值。再比如本地化的日期和数字绑定等等。在其他某些框架中,你只能使用字符串表单对象, 需要手动解析它并转换到业务对象。
-
可定制的handler mapping和view resolution:Spring提供从最简单的URL映射, 到复杂的、专用的定制策略。与某些web MVC框架强制开发人员使用单一特定技术相比,Spring显得更加灵活。
-
灵活的model转换:在Springweb框架中,使用基于
Map
的 键/值对来达到轻易地与各种视图技术的集成。 -
可定制的本地化和主题(theme)解析:支持在JSP中可选择地使用Spring标签库、支持JSTL、支持Velocity(不需要额外的中间层)等等。
-
简单而强大的JSP标签库(Spring Tag Library):支持包括诸如数据绑定和主题(theme) 之类的许多功能。它提供在标记方面的最大灵活性。
-
JSP表单标签库:在Spring2.0中引入的表单标签库,使得在JSP中编写 表单更加容易。
-
Spring Bean的生命周期可以被限制在当前的HTTP Request或者HTTP
Session
。 准确的说,这并非Spring MVC框架本身特性,而应归属于Sping MVC使用的WebApplicationContext容器。
对Spring MVC的介绍参考自官方文档:http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html
Spring MVC工作原理
Spring MVC 分离了控制器、模型对象、分派器以及处理程序对象的角色,这种分离让它们更容易进行定制。
Spring的MVC框架主要由DispatcherServlet、处理器映射、处理器(控制器)、视图解析器、视图组成。
Spring MVC接口解释
- DispatcherServlet:
Spring提供的前端控制器,所有的请求都有经过它来统一分发。在DispatcherServlet将请求分发给Spring Controller之前,需要借助于Spring提供的HandlerMapping定位到具体的Controller。
- HandlerMapping:
能够完成客户请求到Controller映射。
- Controller:
需要为并发用户处理上述请求,因此实现Controller接口时,必须保证线程安全并且可重用。
Controller将处理用户请求,这和Struts Action扮演的角色是一致的。一旦Controller处理完用户请求,则返回ModelAndView对象给DispatcherServlet前端控制器,ModelAndView中包含了模型(Model)和视图(View)。
从宏观角度考虑,DispatcherServlet是整个Web应用的控制器;从微观考虑,Controller是单个Http请求处理过程中的控制器,而ModelAndView是Http请求过程中返回的模型(Model)和视图(View)。
- ViewResolver:
Spring提供的视图解析器(ViewResolver)在Web应用中查找View对象,从而将相应结果渲染给客户。
Spring MVC运行原理
-
客户端请求提交到DispatcherServlet
-
由DispatcherServlet控制器查询一个或多个HandlerMapping,找到处理请求的Controller
-
DispatcherServlet将请求提交到Controller
-
Controller调用业务逻辑处理后,返回ModelAndView
-
DispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModelAndView指定的视图
-
视图负责将结果显示到客户端
DispatcherServlet是整个Spring MVC的核心。它负责接收HTTP请求组织协调Spring MVC的各个组成部分。其主要工作有以下三项:
- 截获符合特定格式的URL请求。
- 初始化DispatcherServlet上下文对应的WebApplicationContext,并将其与业务层、持久化层的WebApplicationContext建立关联。
- 初始化Spring MVC的各个组成组件,并装配到DispatcherServlet中。
Spring MVC与Structs2的差异
- Struts2是类级别的拦截, 一个类对应一个request上下文,Spring MVC是方法级别的拦截,一个方法对应一个request上下文,而方法同时又跟一个url对应。所以说从架构本身上Spring MVC就容易实现Restful URL,而Struts2的架构实现起来要费劲,因为Struts2中Action的一个方法可以对应一个url,而其类属性却被所有方法共享,这也就无法用注解或其他方式标识其所属方法了。
- 由上边原因,Spring MVC的方法之间基本上独立的,独享request response数据,请求数据通过参数获取,处理结果通过ModelMap交回给框架,方法之间不共享变量,而Struts2搞的就比较乱,虽然方法之间也是独立的,但其所有Action变量是共享的,这不会影响程序运行,却给我们编码读程序时带来麻烦,每次来了请求就创建一个Action,一个Action对象对应一个request上下文。
- 由于Struts2需要针对每个request进行封装,把request,session等servlet生命周期的变量封装成一个一个Map,供给每个Action使用,并保证线程安全,所以在原则上,是比较耗费内存的。
- 拦截器实现机制上,Struts2有以自己的interceptor机制,Spring MVC用的是独立的AOP方式,这样导致Struts2的配置文件量还是比Spring MVC大。
- Spring MVC的入口是servlet,而Struts2是filter(这里要指出,filter和servlet是不同的,以前认为filter是servlet的一种特殊),这就导致了二者的机制不同,这里就牵涉到servlet和filter的区别了。
- Spring MVC集成了Ajax,使用非常方便,只需一个注解@ResponseBody就可以实现,然后直接返回响应文本即可,而Struts2拦截器集成了Ajax,在Action中处理时一般必须安装插件或者自己写代码集成进去,使用起来也相对不方便。
- Spring MVC验证支持JSR303,处理起来相对更加灵活方便,而Struts2验证比较繁琐,感觉太烦乱。
- Spring MVC和Spring是无缝的。从这个项目的管理和安全上也比Struts2高(当然Struts2也可以通过不同的目录结构和相关配置做到Spring MVC一样的效果,但是需要xml配置的地方不少)。
- 设计思想上,Struts2更加符合OOP的编程思想, Spring MVC就比较谨慎,在servlet上扩展。
- Spring MVC开发效率和性能高于Struts2。
- Spring MVC可以认为已经100%零配置。