• 对Spring 及SpringMVC的理解


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

  • 相关阅读:
    两种接口传送数据协议(xml和json)
    两种访问接口的方式(get和post)
    myeclipse 编写java代码提示 dead code 原因
    svn文件冲突,树冲突详解
    linux操作提示:“Can't open file for writing”或“operation not permitted”的解决办法
    embed标签属性
    程序员必读的书刊收藏
    python实现冒泡排序和快速排序
    python简单词频统计
    Qt出现堆溢出(Error Code -1073741823)
  • 原文地址:https://www.cnblogs.com/tuojunjie/p/6383485.html
Copyright © 2020-2023  润新知