SpringMVC+Spring阅读笔记——SpringMVC概览

来源:互联网 发布:json转化为数组的方法 编辑:程序博客网 时间:2024/06/07 08:34

(http://downpour.iteye.com/blog/1330596) 

问题
项目规模扩大之后,请求-响应的映射关系全部定义在web.xml中,将造成web.xml的不断膨胀而变得难以维护。


针对这个问题,SpringMVC提出的方案就是:提炼一个核心的Servlet覆盖对所有Http请求的处理。。 

这一被提炼出来的Servlet,通常被我们称之为:核心分发器。在SpringMVC中,核心分发器就是org.springframework.web.servlet.DispatcherServlet。 

:核心分发器的概念并非SpringMVC独创。我们可以看到,核心分发器的提炼几乎是所有MVC框架设计中的必经之路。在Struts2中,也有核心分发器(Dispatcher)的概念,只是它并不以Servlet的形式出现。因此,读者应该把关注点放在核心分发器这个概念的提炼之上,而不是纠结于其形式。 

有了DispatcherServlet,我们至少从表面上解决了上面的问题。至少在web.xml中,我们的配置代码就被固定了下来: 

  <servlet>    <servlet-name>mvc-dispatcher</servlet-name>    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>    <load-on-startup>1</load-on-startup>  </servlet>  <servlet-mapping>    <servlet-name>mvc-dispatcher</servlet-name>    <url-pattern>/</url-pattern>  </servlet-mapping>

在这里,<url-pattern>定义了整个请求-响应的映射载体:URL;而<servlet-name>则将<servlet>节点和<servlet-mapping>节点联系在一起形成请求-响应的映射关系;<servlet-class>则定义了具体进行响应的Servlet实现类。 


有了DispatcherServlet,我们只相当于迈出了坚实的第一步,因为对核心Servlet的提炼不仅仅是将所有的Servlet集中在一起那么简单,我们还将面临两大问题: 

问题
核心Servlet应该能够根据一定的规则对不同的Http请求分发到不同的Servlet对象上去进行处理。

问题
核心Servlet应该能够建立起一整套完整的对所有Http请求进行规范化处理的流程。


而这两大问题的解决,涉及到了DispatcherServlet的设计核心。我们也不得不引入另外一个重要的编程元素,那就是:组件。 

【组件的引入】 

DispatcherServlet的引入是我们通过加入新的编程元素来对基本的Servlet规范进行抽象概括所迈出的第一步。不过接下来,有关DispatcherServlet的设计问题又一次摆到了我们的面前。 

如果仔细分析一下上一节末尾所提出的两个问题,我们可以发现这两个问题实际上都涉及到了DispatcherServlet的处理过程,这一处理过程首先必须是一剂万能药,能够处理所有的Http请求;同时,DispatcherServlet还需要完成不同协议之间的转化工作(从Http协议到Java世界的转化)。 

对此,SpringMVC所提出的方案是:将整个处理流程规范化,并把每一个处理步骤分派到不同的组件中进行处理。 

这个方案实际上涉及到两个方面: 

  • 处理流程规范化 —— 将处理流程划分为若干个步骤(任务),并使用一条明确的逻辑主线将所有的步骤串联起来
  • 处理流程组件化 —— 将处理流程中的每一个步骤(任务)都定义为接口,并为每个接口赋予不同的实现模式
在SpringMVC的设计中,这两个方面的内容总是在一个不断交叉、互为补充的过程中逐步完善的。 

处理流程规范化是目的,对于处理过程的步骤划分和流程定义则是手段。因而处理流程规范化的首要内容就是考虑一个通用的Servlet响应程序大致应该包含的逻辑步骤: 

  • 步骤1 —— 对Http请求进行初步处理,查找与之对应的Controller处理类(方法)
  • 步骤2 —— 调用相应的Controller处理类(方法)完成业务逻辑
  • 步骤3 —— 对Controller处理类(方法)调用时可能发生的异常进行处理
  • 步骤4 —— 根据Controller处理类(方法)的调用结果,进行Http响应处理
这些逻辑步骤虽然还在我们的脑海中,不过这些过程恰恰正是我们对整个处理过程的流程化概括,稍后我们就会把它们进行程序化处理。 

所谓的程序化,实际上也就是使用编程语言将这些逻辑语义表达出来。在Java语言中,最适合表达逻辑处理语义的语法结构是接口,因此上述的四个流程也就被定义为了四个不同接口,它们分别是: 

  • 步骤1 —— HandlerMapping
  • 步骤2 —— HandlerAdapter
  • 步骤3 —— HandlerExceptionResolver
  • 步骤4 —— ViewResolver
查看DispatchServlet的源码后,可以看到DispatcherServlet的核心逻辑不过是对组件的获取和调用。 

除此之外,SpringMVC对处理流程的规范化和组件化所引出的另外一个问题就是如何针对所有的组件进行管理。 

先说说管理。其实管理这些组件对于SpringMVC来说完全不是问题,因为SpringMVC作为Spring Framework的一部分,其自身的运行环境就是Spring所定义的容器之中。我们知道,Spring Framework的核心作用之一就是对整个应用程序的组件进行管理。所以SpringMVC对于这些已定义组件的管理,只不过是借用了Spring自身已经提供的容器功能而已。 

:SpringMVC在进行组件管理时,会单独为SpringMVC相关的组件构建一个容器环境,这一容器环境可以独立于应用程序自身所创建的Spring容器。有关这一点,我们在之后的讨论中将详细给出分析。 

而SpringMVC对这些组件的管理载体,就是我们在上一节中所提到的核心配置文件。我们可以看到,核心配置文件在整个SpringMVC的构成要素中占有一席之地的重要原因就是在于:我们必须借助一个有效的手段对整个SpringMVC的组件进行定义,而这一点正是通过核心配置文件来完成的。 

SpringMVC就是通过DispatcherServlet将一堆组件串联起来的Web框架。


SpringMVC的设计原则


【Open for extension / closed for modification】 

(同时也是Spring框架的设计原则,为用户预留扩展点,但不允许对原框架的修改)



结论  子类不允许通过继承的方式改变父类的默认行为。父类将其的核心方法声明为private。
结论  不允许外部程序对这些系统配置类进行访问,从而杜绝外部程序对SpringMVC默认行为的任何修改。
结论  SpringMVC提供的扩展切入点无法改变框架默认的行为方式。


SpringMVC的框架简化历程

这里说的简化,其实包含的内容非常广泛。笔者在这里挑选了两个比较重要的方面来进行说明: 

  • Annotation —— 简化各类配置定义
  • Schema Based XML —— 简化组件定义
先谈谈Annotation。Annotation是JDK5.0带来的一种全新的Java语法。这种语法的设计初衷众说纷纭,并没有一个标准的答案。笔者在这里给出一个个人观点以供参考: 

结论 Annotation的原型是注释。作为一种对注释的扩展而被引入成为一个语法要素,其本身就是为了对所标注的编程元素进行补充说明,从而进一步完善编程元素的逻辑语义。

从这个结论中,我们可以看到一层潜在的意思:在Annotation出现之前,Java自身语法所定义的编程元素已经不足以表达足够多的信息或者逻辑语义。在这种情况下,过去经常使用的方法是引入新的编程元素(例如使用最多的就是XML形式的结构化配置文件)来对Java程序进行补充说明。而在Annotation出现之后,可以在一定程度上有效解决这一问题。因此Annotation在很长一段时间都被当作是XML配置文件的替代品。 

这也就是Annotation经常被用来和XML进行比较的原因。孰优孰劣其实还是要视具体情况而定,并没有什么标准答案。不过我们在这里想强调的是Annotation在整个SpringMVC中所起到的作用,并非仅仅是代替XML那么简单。我们归纳了有三个不同的方面: 

1. 简化请求映射的定义 

在Spring2.5之前,所有的Http请求与Controller核心处理器之间的映射关系都是在XML文件中定义的。作为XML配置文件的有效替代品,Annotation接过了定义映射关系的重任。我们可以将@RequestMapping加在Controller的class-level和method-level进行Http请求的抽象。 

2. 消除Controller对接口的依赖 

在Spring2.5之前,SpringMVC规定所有的Controller都必须实现Controller接口: 
也就是说,应用程序不得不严重依赖于接口所规定的处理模式。而我们看到Controller接口除了对处理接口的返回值做了一次封装以外,我们依然需要面对原生的HttpServletRequest和HttpServletResponse对象进行操作。 

而在Spring2.5之后,我们可以通过@Controller来指定SpringMVC可识别的Controller,彻底消除了对接口的依赖:
 

Java代码  收藏代码
  1. @Controller  
  2. public class UserController {  
  3.       // 这里省略了许多代码  
  4. }  


3. 成为框架进行逻辑处理的标识 

之前已经谈到,Annotation主要被用于对编程元素进行补充说明。因而Spring就利用这一特性,使得那些被加入了特殊Annotation的编程元素可以得到特殊的处理。例如,SpringMVC引入的@SessionAttribute、@RequestBody、@ModelAttribute等等,可以说既是对Controller的一种逻辑声明,也成为了框架本身对相关元素进行处理的一个标识符。 



本文从逻辑上讲,可以分成三个部分: 

  • SpringMVC的构成要素 —— 是什么 —— 阐述框架的主体结构
  • SpringMVC的发展历程 —— 为什么 —— 阐述框架各要素产生的内因
  • SpringMVC的设计原则 —— 怎么样 —— 阐述框架的共性思想
“是什么”是框架最根本的问题。我们从SpringMVC的三要素入手,帮助大家分析构成SpringMVC的基本元素主要是为了让读者对整个SpringMVC的架构有一个宏观的认识。在之后的分析中,我们研究的主体内容也将始终围绕着这些SpringMVC的构成要素,并进行逐一分析。 

“为什么”是框架的存在基础。我们可以看到,整个SpringMVC的发展历程是一个对于开发模式不断进行优化的过程,也是不断解决Web开发中所面临的一个又一个问题的过程。之前我们也曾经提到过一个重要观点:任何框架无所谓好与坏、优与劣,它们只是在不同的领域解决问题的方式不同。所以,我们分析这些SpringMVC基本构成要素产生的原因实际上也是对整个Web开发进行重新思考的过程。 

“怎么样”是一种深层次的需求。对于SpringMVC而言,了解其基本构成和用法并不是一件难事,但是要从中提炼并总结出一些共性的东西就需要我们能够站在一个更高的高度来进行分析。也只有了解了这些共性的东西,我们才能进一步总结出使用框架的最佳实践。 


0 0
原创粉丝点击