最近在看Spring MVC的源码,就把自己对MVC模式和对各种框架的实现的认识写出来给大家看看,算是一个总结.所以,恳请大家用怀疑的眼光来看待这篇文章,假如有认识不对的地方,麻烦指出.
MVC与WEB应用
MVC是什么就不用我多说了.对于现有较成熟的Model-View-Control(MVC)框架而言,其注意的主要问题无外乎下面这些:
Model:
模型应该包含由视图显示的数据.在J2EE Web应用中,数据通常应该由普通的javabean组成.一旦一个控制器选择了视图,模型就要包含视图相应的数据.模型本身不应该进一步的访问数据,也不应该和业务对象相联系.
模型要解决的问题包括:
l 封装要显示的数据
l 我不认为模型要依赖于特定的框架
l 不一定非得是javabean
View:
视图负责显示出模型包含的信息,视图不必了解控制器或是底层业务对象的具体实现
视图要解决的问题包括:
l 在显示给定数据模型的情况下显示内容
l 不应该包含有业务逻辑
l 可能需要执行显示逻辑,比如颜色交替的显示某个数组的各行
l 视图最好不处理验证的错误,数据的验证应该在由其他组件完成
l 视图不应该处理参数,参数应该交由控制器集中处理
Control:
控制器就好像MVC里的中枢神经,它也许会需要一些助手来帮助它比如解析视图,解析参数等.控制器可以访问到业务对象或者是它的代理是很重要的,比如Struts里的Action.
控制器要解决的问题包括:
l 检查和抽取请求参数
l 调用业务对象,传递从请求中获取的参数
l 创建模型,视图讲显示对应的模型
l 选择一个合适的视图发送给客户端
l 控制器有时不会只有一个
现有的框架
现在已经有很多的MVC的框架实现.比较流行的应该就是Struts和Webwork了
Struts
这是最流行的web框架,几乎成为了实际上的工业标准.除了上面讨论的MVC模式应该有的优点以外.它还有如下一些缺点:
l 每个Action只生成一次,然后就被缓存起来,再次请求这个Action的时候就不会生成新的对象,而是重复使用第一次生成的对象,这就意味着每个Action必须是线程安全的
l 采用ActionForm封装了表单数据,但是却只能对应String类型的数据, 虽然它可以使用工具Commons Beanutils进行类型转化,但是仅仅是提供了对象级别的支持
l 严重的依赖于Servlet API, 测试比较困难(不过下一版Struts里的Action.execute的方法签名讲会换成execute(ActionContext actionContext),依赖也许不会那么严重)
l 框架本身的验证规则比较简单,一般都是依赖于Commons Validation进行验证
l 想在Action前后做些处理很困难.有时甚至不得不自己去写专门的控制器
l 由于Struts都是具体的类继承,这样很容易打破封装?
l 提供各式各样的自定义的标签,但是数据绑定太原始了,这样就使页面代码依赖于Struts这个特定的框架,而它却不是规范,我觉得这是很致命的
l 它太面向JSP了,尽管使用其他视图技术是有可能的,但是使用的时候却不是很方便
Webwork
这个框架虽然我没使用过,但是却一直在关注它的发展
Webwork的设计思想采用了比Struts更为聪明的一种方式,就技术角度上说比Struts要高出不少.它以Command模式为基础.分为Xwork和Webwork,而且框架并不依赖于Servlet API.
Xwork提供了很多核心功能:拦截器(Interceptor),运行时表单验证,类型转换,IoC容器等.
WebWork建立在Xwork之上,用于处理基于HTTP的响应和请求.用Map和ActionContext封装了Session,Application等这些Servlet对象.从而解除了和Servlet API的耦合.
但是它仍然不是完美的:
l 为每一个请求都创建一个Action可能有些浪费.(但是Servlet引擎也是为每个请求创建多个对象,但是也没看出来对性能有多大的影响?)
l 当项目越来越大的时候,配置文件可能会很零乱.好像它不支持多个配置文件
l 异常处理是Command模式里值得注意的问题:我们不知道某一特定命令可能会抛出什么特定的异常,所以execute()被迫抛出异常,而不论异常是运行时异常,还是已检查异常
Spring MVC Framework的目标
上面说了一些MVC的原理,以及现在主流框架的一些问题,现在来看Spring是如何处理的. Spring MVC框架根据不同的角色定义了很多接口,但是它最大的问题也是依赖于Servlet API
Spring MVC Framework有这样一些特点:
l 它是基于组件技术的.全部的应用对象,无论控制器和视图,还是业务对象之类的都是java组件.并且和Spring提供的其他基础结构紧密集成.
l 不依赖于Servlet API(目标虽是如此,但是在实现的时候确实是依赖于Servlet的)
l 可以任意使用各种视图技术,而不仅仅局限于JSP
l 支持各种请求资源的映射策略
l 它应是易于扩展的
我认为评价一个框架,应该有几个原则
l 它应该是易于使用的,易于测试的
Spring 易于使用吗?我不这么觉得,尤其是它的配置文件.在最恐怖的情况下,各种业务逻辑,基础设施也许会拥挤在一个配置文件里.而如事务处理这些基础设施应该是由容器管理而不是开发人员,就算把这些分开到几个配置文件里,逻辑上虽然清晰了,但是基础设置却还是暴露在外边
Spring易于测试吗?对Spring进行单元测试很容易,测试起来很方便
l 应该在多个层次上提供接口
Spring提供了很多接口,而几乎每个接口都有默认的抽象实现,每个抽象实现都有一些具体实现,所以在可扩展性这点上Spring无疑是很优秀的
l 框架内部和框架外部应该被区别对待
框架内部可以很复杂,但是使用起来一定要简单,Spring的内部比较麻烦,但是它很好的隐藏了这种复杂性,使用起来很舒服,比如设置一个bean的属性.仅仅是setPropertyValue
(String propertyName, Object value)就完成,至于怎么去设置,Spring完全隐藏了这种复杂性
l 完善的文档和测试集
这个就不用说了,老外的东西,都很完善
Spring Web框架基本流程
知道了Spring MVC框架,现在来看看它的流程
Spring MVC Framework大至流程如下:
当web程序启动的时候,ContextLoaderServlet会把对应的配置文件信息读取出来,通过注射去初始化控制器DispatchServlet. 而当接受到一个HTTP请求的时候, DispatchServlet会让HandlerMapping去处理这个请求.HandlerMapping根据请求URL(不一定非要是URL,完全可以自定义,非常灵活)来选择一个Controller. 然后DispatchServlet会在调用选定的Controller的handlerRequest方法,并且在这个方法前后调用这个Controller的interceptor(假如有配置的话),然后返回一个视图和模型的集合ModelAndView.框架通过ViewResolver来解析视图并且返回一个View对象,最后调用View的render方法返回到客户端
DispatcherServlet
这是框架的控制器,是一个具体类,它通过运行时的上下文对象来初始化.控制器本身并不去控制流程,而只是是Controller的”控制器”,他只是把处理请求的责任委托给了对应的Controller.
控制器继承自抽象基类FrameworkServlet,它的属性webApplicationContext就代表着这个web程序上下文,而这个上下文对象默认实现就是从一个XML文件读取配置信息(当然也可以是其他文件格式). WebApplicationContext其实是beans包的东西,这个包提供了这个Spring整个框架的基础结构,以后我会分析这个包的内容.但是现在仅仅需要知道WebApplicationContext代表一个web应用的上下文对象.
现在来看看DispatchServlet是如何工作的:
DispatchServlet由于继承自抽象基类FrameworkServlet,而FrameworkServlet里的doGet(),doPost()方法里有调用serviceWrapper(),跳到serviceWrapper()里去看,结果发现它有把具体实现委托给了doService(request, response); 方法.所以现在已经很清楚了, DispatchServlet真正实现功能的是doService() 这个方法.
特别的, FrameworkServlet的initFrameworkServlet()这个方法是控制器的初始化方法,用来初始化HandlerMappings之类的对象,这也是延迟到子类实现的.其实就是一个Template模式的实现.don’t call us, we will call u.总的看来,Spring就是通过这样来实现它的控制反转的:用框架来控制流程,而不是用户
跳到doService()一看究竟,就会发现真正工作的又是另一个助手函数doDispatch(request, response),没办法,继续看下去,发现这样两行代码
HandlerExecutionChain mappedHandler = null;
mappedHandler = getHandler(processedRequest, false);
看HandlerExecutionChain源码就发现它其实就是对Controller和它的Interceptors的进行了包装;
getHandler()就是从HandlerMappings(这是一个List,存放的handlerMapping对象)中取出对应的handlerMapping对象, 每个HandlerMapping对象代表一个Controller和URL的映射(其实在运行的时候是一个HandlerExecutionChain和URL的映射,而HandlerExecutionChain对象其实就是对Controller和它interceptors的一个包装器,可以把HandlerMapping看成Controller和URL的映射).而这个HandlerMapping是通过配置文件在运行时注射进来的,一般是SimpleUrlHandlerMapping这个子类
取得了HandlerMapping对象,继续向下看,发现:
if (mappedHandler.getInterceptors() != null) {
for (int i = 0; i < mappedHandler.getInterceptors().length; i++) {
HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i];
if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
return;
}
interceptorIndex = i;
}
}
这里就是在调用Controller的拦截器,原理就是这句了:
interceptor.preHandle(processedRequest, response, mappedHandler.getHandler(), mv);
preHandle方法传入了mappedHandler.getHandler()这个参数来实现递归调用!而interceptor.postHandle方法如此一般.只不过这个方法是在handleRequest方法后调用
继续看下去:
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
发现Controller的handleRequest真正的操作又被代理给了HandlerAdapter的handle方法,并且返回一个ModelAndView,我想这里增加一层的意义应该是为了解除Controller和DispatchServlet的耦合吧.
接着就很简单了,调用render()方法,在这个方法里面由ViewResoler解析出视图名,再调用视图对象的render方法把合适的视图展现给用户
到此,控制器的流程就OVER了
HandlerMapping
通过使用HandlerMapping,控制器可以用URL和某一个Controller进行标准的映射,而实现URL映射的具体子类的UrlHandlerMapping.
Spring还允许我们自定义映射,比如通过Session,cookie或者用户状态来映射.而这一切仅仅只需要实现HandlerMapping接口而已.不过URL映射已经能满足大部分的要求
Controller
Controller 类似Structs的Action, Controller接口只有一个方法handleRequest(),放回一个ModelAndView对象,如同设计目标所说的那样,每个Controller都是一个java组件,所以它可以在上下文环境中任意配置,组件属性都会在初始化的时候被配置.Spring自己提供了几个具体的实现.方便我们使用
ViewResolver
Controller通常返回包含视图名字而不是视图对象的ModelAndView对象.从而彻底的解除了控制器和视图之间的耦合关系,并且在这里还可以提供国际化的支持.
在你的配置文件中你可以:
welcomeView.class = org.springframework.web.servlet.view. InternalResourceView
welcomeView.url=/welcome.jsp
也可以
welcomeView.class = org.springframework.web.servlet.view.xslt. XsltView
welcomeView.url=/xslt/default.xslt
View
这也是一个java组件,它不做任何请求处理或是业务逻辑,它仅仅获取模型传递的数据,并把数据显示出来.它里面的 render方法按照如下流程工作:
l 设置模型的数据到request作用域
l 取得视图的URL
l 转发到对应的URL
总结:
Spring的web框架是一个很优秀的框架,在这里只是走马观花的分析了Spring的工作流程和一些关键的类,但是并没有去深入的去探讨它背后所体现的思想,还有它的优缺点等东西.这些都等下次再说吧
这里再次说明一下,上面说的只是我自己的想法,假如有不理解或者不正确的地方,请在下面留言指出或者查看官方的<Spring-Reference>,以后会逐渐推出自己对Spring其他的理解
相关推荐
本文档详细介绍了如何使用Spring Framework MVC框架逐步构建一个完整的Web应用程序。文档版本为2.5,由Thomas Risberg、Rick Evans和Portia Tung共同编著,版权归属2004-2008年。 #### 基本应用及环境搭建 ##### ...
Spring MVC is a lightweight application framework that comes with a great configuration by default. Being part of the Spring Framework, it naturally extended and supported it with an amazing set of ...
spring-framework-4.3.6.RELEASE - 解包大小为 44.9 MB ## Spring Framework The Spring Framework provides a comprehensive programming and configuration model for modern Java-based enterprise applications ...
3. New Features and Enhancements in Spring Framework 4.0 ............................................ 17 3.1. Improved Getting Started Experience .........................................................
Chapter 2: Spring Framework Fundamentals .......................................................25 Chapter 3: Web Application Architecture...........................................................
3. New Features and Enhancements in Spring Framework 4.0 ............................................ 17 3.1. Improved Getting Started Experience .........................................................
Build mission-critical enterprise applications using Spring Framework and Aspect Oriented Programming About This Book Step into more advanced features of aspect-oriented programming and API ...
Get to know the basics of Spring development and gain fundamental knowledge about why and where to use Spring Framework Explore the power of Beans using Dependency Injection, wiring, and Spring ...
You will then learn about a variety of authentication mechanisms and how to integrate them easily with the Spring MVC application. You will also understand how to achieve authorization in a Spring ...
If you want to learn how to get around the Spring framework and use it to build your own amazing applications, then this book is for you. Beginning with an introduction to Spring and setting up the ...
27.1. The “Spring Web MVC Framework” 27.1.1. Spring MVC Auto-configuration 27.1.2. HttpMessageConverters 27.1.3. Custom JSON Serializers and Deserializers 27.1.4. MessageCodesResolver 27.1.5. Static...
Spring is the most popular Java web framework. It makes it easy to efficiently build modular and testable web applications by using the Model-View-Controller paradigm and dependency injection. Using ...
在实际开发中,Spring Framework常常与其他技术结合使用,例如Spring Boot与Spring Cloud的组合,可以构建分布式微服务系统。Spring Data项目则为各种数据存储(如NoSQL数据库、图形数据库)提供了统一的访问接口。 ...
SSM stands for Spring, Spring MVC, and MyBatis, which are popular Java frameworks used for building web applications. Spring provides the core container for managing beans and dependencies, Spring ...
在处理页面跳转时,通常会用到Spring Boot的 MVC(Model-View-Controller)架构模式。MVC模式帮助分离业务逻辑、数据模型和用户界面,使得代码更易于维护和扩展。 在Spring Boot中,我们可以创建一个`Controller`类...
Mocking spring MvC 80- Testing web security 83 4.3 Testing a running application 86 Starting the server on a random port 87. Testing HTML pages with selenium 88 4.4 Summary 90 Getting Groovy with the ...