对Spring 及SpringMVC的理解

原文地址:

http://blog.csdn.net/pineapple0/article/details/40888153

Spring是一个轻型容器(light-weight container),其核心是Bean工厂(Bean Factory),用以构造我们所需要的M(Model)。在此基础之上,Spring提供了AOP(Aspect-Oriented Programming, 面向层面的编程)的实现,用它来提供非管理环境下申明方式的事务、安全等服务;对Bean工厂的扩展ApplicationContext更加方便我们实现J2EE的应用;DAO/ORM的实现方便我们进行数据库的开发;Web MVC和Spring Web提供了Java
Web应用的框架或与其他流行的Web框架进行集成。

1)开源框架
2)IoC(控制反转),将类的创建和依赖关系写在配置文件里,由配置文件注入,实现了松耦合
3)AOP 将安全,事务等于程序逻辑相对独立的功能抽取出来,利用spring的配置文件将这些功能插进去,实现了按照方面编程,提高了复用性

前言

最近在看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的工作流程和一些关键的类,但是并没有去深入的去探讨它背后所体现的思想,还有它的优缺点等东西.这些都等下次再说吧

时间: 2024-09-08 21:01:54

对Spring 及SpringMVC的理解的相关文章

Spring+Mybatis+SpringMVC后台与前台分页展示实例(附工程)(转)

   林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka        摘要:本文实现了一个后台由Spring+Mybatis+SpringMVC组成,分页采用PageHelper,前台展示使用bootstrap-paginator来显示效果的分页实例.整个项目由maven构成.这里主要讲了分页的实例,框架怎么搭建就不再说明,主要是在这里的基础上来增加分页功能的.注意,此文是在这个基础 Spring+Mybatis+SpringMVC+Mav

ajax框架-用Spring,Springmvc,mybatis实现新用户注册并验证保存

问题描述 用Spring,Springmvc,mybatis实现新用户注册并验证保存 注册,将新用户输入的信息提交并进行验证,验证可采用验证框架也可采用validate,验证失败返回注册页面显示错误信息,验证成功后保存用户数据. 登陆,验证,失败后返回登陆页面显示错误信息,验证成功后保存用户信息至session. 登陆成功后,将所有用户数据展示给用户,列出用户详细信息,并分页.用拦截器判断,如果没有登陆的话返回登陆页面并提示用户没有登陆 1.Ioc注入全部采用Spring注解型注入. 2.使用m

logback与Spring、SpringMVC结合使用教程(转) logback good

        摘要:本文主要介绍了如何在spring.springMVC中使用logback 一.logback与Spirng结合使用 1.maven添加引用:   [html] view plain copy     <dependency>       <groupId>log4j</groupId>       <artifactId>log4j</artifactId>       <version>${log4j.vers

SSM框架(二)--Spring、SpringMVC和MyBatis整合(详细教程)

一定要记得下载代码,自己对照教程敲一遍理解,百看不如一练 GitHub下载源码地址 SSM框架(一)–Spring和MyBatis整合(详细教程) 毋庸置疑,这个肯定是接着上一篇的讲,不过其实也不然,就复制上一工程的几个配置文件罢了,其实没多大联系,因为这个配置是我们学过MyBaits的逆向工程之后来配置. MyBaits的逆向工程 还是给个jar包 mybatis与spring整合全部jar包(包括springmvc) 还是给个SQL ssm测试sql 先谈谈springmvc和mybatis

spring mvc-maven+springmvc 报错,找了一下午没解决。哪位大神帮忙看看。

问题描述 maven+springmvc 报错,找了一下午没解决.哪位大神帮忙看看. SEVERE: Error configuring application listener of class org.springframework.web.context.ContextLoaderListener java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener at org.ap

spring mvc-JPA+springMVC的分页问题

问题描述 JPA+springMVC的分页问题 在做jpa分页的时候带参数时,执行到图片红色部分老师报错,不清楚searchParams参数集的格式问题还是怎么回事,谁能贴出action部分的代码看下.或者解惑下.谢谢!!! 解决方案 终于找到问题了,前面传入得searchParams 的格式不正确 应该是searchParams.put(key, 前台传入参数 ); key的格式应该为Operator.(EQ, LIKE, GT, LT, GTE, LTE)_字段名称 .来命名否则报错.如:

spring mvc-nginx springmvc路径问题

问题描述 nginx springmvc路径问题 nginx怎么配置静态文件(如css,js,png)由nginx处理,而其它动态访问交给后台tomcat处理,最主要的问题在于spring mvc的路径不是像.do/jsp带后缀,所以这样的路径在nginx怎么配置? 解决方案 基于 Nginx XSendfile + SpringMVC 进行文件下载使用 nginx 作为代理服务器的路径问题nginx 的web路径权限问题 解决方案二: 参考,http://stackoverflow.com/q

spring mvc-EXTJS4 SpringMVC框架的一个问题

问题描述 EXTJS4 SpringMVC框架的一个问题 如图,是一个通用后台管理模板,上方和下方没截图,现在想页面一加载就在右边生成一个表格来显示数据,刚接触这个框架,项目比较急,求帮忙... PS:用jsp来做可以很快,没办法- -一定要用这个框架,顺便给点学习资料那就感激不尽了,现在看着真的不懂 很乱感觉 解决方案 可以参考一下 <EXT JS权威指南> 该框架控件都是封装好的,就是初始化调用的时候对于刚接触的选后来说不太习惯. 如果JS底子比较好的话,建议你上官网看一下demo ,像这

Spring入门指引之理解Spring的打包方式

打包 获取Spring发布包之后,你或许会惊讶的发现:Spring开发小组并没有用单个JAR文件来包含所有代码,而是选择建立包含有完整发布的单个JAR和8个独立JAR文件来包含对应的Spring组件.未来版本的组件JAR文件数量很可能会有所增加,可令你更加自如的选择自己的代码要包含的特性. 完整发布包 所有发布版本都提供spring.jar文件,它差不多包含Spring framework类的完整发布包.之所以说"差不多"是因为它实际上并未包含任何mock类,这些类随Spring一起发