SpringMVC深度探险(二) —— SpringMVC概览
本文是专栏文章(SpringMVC深度探险)系列的文章之一,博客地址为:http://downpour.iteye.com/blog/1330596。
对于任何事物的研究,总是由表及里、由浅入深地进行。在本系列的第二篇文章中,我们将通过不同的观察视角,对SpringMVC做一些概要性的分析,帮助大家了解SpringMVC的基本构成要素、SpringMVC的发展历程以及SpringMVC的设计原则。
SpringMVC的构成要素
了解一个框架的首要任务就是搞清楚这个框架的基本构成要素。当然,这里所说的构成要素实际上还可以被挖掘为两个不同的层次:
基于框架所编写的应用程序的构成要素框架自身的运行主线以及微观构成要素我们在这里首先来关注一下第一个层次,因为第一个层次是广大程序员直接能够接触得到的部分。而第二个层次的讨论,我们不得不在第一个层次的讨论基础之上通过不断分析和逻辑论证慢慢给出答案。
在上一篇文章中,我们曾经列举了一段SpringMVC的代码示例,用于说明MVC框架的构成结构。我们在这里不妨将这个示例细化,总结归纳出构成SpringMVC应用程序的基本要素。
1. 指定SpringMVC的入口程序(在web.xml中)
SpringMVC自身由众多不同的组件共同构成,而每一个组件又有众多不同的实现模式。这里的SpringMVC核心配置文件是定义SpringMVC行为方式的一个窗口,用于指定每一个组件的实现模式。有关SpringMVC组件的概念,在之后的讨论中也会涉及。
3. 编写控制(Controller)层的代码
从图中我们可以发现,所有的MVC框架都是从基本的Servlet模型发展而来。因此,要了解SpringMVC的发展历程,我们还是从最基本的Servlet模型开始,探究SpringMVC对于Servlet模型的改造过程中究竟经历了哪些阶段、碰到了哪些问题、并看看SpringMVC是如何解决这些问题的。
【核心Servlet的提炼】
在Servlet模型中,请求-响应的实现依赖于两大元素的共同配合:
1. 配置Servlet及其映射关系(在web.xml中)
控制流和数据流的问题几乎贯穿了所有MVC框架的始末,因而我们不得不在这里率先提出来,希望对读者有一些警示作用。
注:对于控制流和数据流的相关概念,请参考另外一篇博客:《Struts2技术内幕》 新书部分篇章连载(五)—— 请求响应哲学。这一对概念,几乎是所有MVC框架背后最为重要的支撑,读者应该尤其重视!
所有MVC框架的核心问题也由控制流和数据流这两大体系延伸开来。比如,在Servlet编程模型之下,“请求-响应映射关系的定义”这一问题就会随着项目规模的扩大而显得力不从心:
我们在之后篇文章中将重点对这里所提到的所有组件做深入的分析。大家在这里需要理解的是SpringMVC定义这些组件的目的和初衷。
这些组件一旦被定义,自然而然也就引出了下一个问题:这些组件是如何串联在一起的?这个过程,是在DispatcherServlet中完成的。有关这一点,我们可以从两个不同的角度加以证明。
1. 从DispatcherServlet自身数据结构的角度
如图中所示,DispatcherServlet中包含了众多SpringMVC的组件,这些组件是实现DispatcherServlet核心逻辑的基础。
2. 从DispatcherServlet的核心源码的角度
这四个方面的内容,我们是顺着设计思路的不断推进而总结归纳出来的。这也恰好证明之前所提到的一个重要观点,我们在这里强调一下:
上图就是HandlerMapping接口的树形实现体系。在这个实现体系结构中,每一个树形结构的末端实现都是SpringMVC中比较具有典型意义的行为模式。我们可以截取其中的几个实现来加以说明:
BeanNameUrlHandlerMapping —— 根据Spring容器中的bean的定义来指定请求映射关系SimpleUrlHandlerMapping —— 直接指定URL与Controller的映射关系,其中的URL支持Ant风格DefaultAnnotationHandlerMapping —— 支持通过直接扫描Controller类中的Annotation来确定请求映射关系RequestMappingHandlerMapping —— 通过扫描Controller类中的Annotation来确定请求映射关系的另外一个实现类有关这几个实现类的具体示例和使用说明,读者可以参考不同版本的Spring官方文档来获取具体的细节。
注:我们在这里之所以要强调不同版本的Spring官方文档的原因在于这些不同的实现类,正代表了不同版本SpringMVC在默认行为模式上选择的不同。在下图中,我们列出了不同重大版本的SpringMVC的实现体系结构,并用红色框圈出了每个版本默认的实现类。
我们可以看到,上述这些不同的HandlerMapping的实现类,其运行机制和行为模式完全不同。这也就意味着对于HandlerMapping这个组件而言,可以进行选择的余地就很大。我们既可以选择其中的一种实现模式作为默认的行为模式,也可以将这些实现类依次串联起来成为一个执行链。不过这已经是实现层面和设计模式上的小技巧了。
单就HandlerMapping一个组件,我们就能看到各种不同的行为模式。如果我们将逻辑主线中所有的组件全部考虑进来,那么整个实现机制就会随着这些组件实现体系的不同而表现出截然不同的行为方式了。因此,我们的结论是:
可以看到,几乎所有的核心处理方法全部被定义成了带有红色标记的private方法,这就充分表明了SpringMVC对于“子类扩展”这种方式的态度:
图中的代码是DispatcherServlet中的核心方法doDispatch,我们这里使用了比较工具将Spring3.1中的实现代码和Spring2.0.8中的实现代码做了比较,其中的区别之处比较工具使用了不同的颜色标注了出来。
我们可以很明显地看到,虽然Spring2.0到Spring3.1之间,SpringMVC的行为方式已经有了翻天覆地的变化,然而整个DispatcherServlet的核心处理主线却并没有很大的变化。这种稳定性,恰巧证明了整个SpringMVC的体系结构设计的精妙之处。
【简化、简化、还是简化】
在Spring2.5之前的SpringMVC版本并没有很强的生命力,因为它只是通过组件将整个MVC的概念加以诠释,从开发流程的简易度来看并没有很明显的提升。有关SpringMVC发展的里程碑,我们将在之后篇文章中重点讲述。我们在这里想要谈到的SpringMVC的另外一大设计原则,实际上主要是从Spring2.5这个版本之后才不断显现出来的。这条设计原则可以用2个字来概括:简化。
这里说的简化,其实包含的内容非常广泛。笔者在这里挑选了两个比较重要的方面来进行说明:
Annotation —— 简化各类配置定义Schema Based XML —— 简化组件定义先谈谈Annotation。Annotation是JDK5.0带来的一种全新的Java语法。这种语法的设计初衷众说纷纭,并没有一个标准的答案。笔者在这里给出一个个人观点以供参考:
![]()
![]()
![]()
可惜文章部分看不到 可惜文章部分看不到
什么是部分看不到? 可惜文章部分看不到
什么是部分看不到?
浏览器问题! 楼主继续啊,期待楼主后面的文章! 15 楼 chrisliu 2012-02-03 期待下一篇的出现。支持楼主! 16 楼 fancyboy2050 2012-02-07 好文章,求楼主继续。 17 楼 senton 2012-02-10 太能写了,淫才啊 18 楼 fenghuazh 2012-02-14 有点太书面化了。 19 楼 fenghuazh 2012-02-14 有点太书面化了。简简单单的阐述一个问题多好啊。 20 楼 ganjp 2012-02-16 fenghuazh 写道有点太书面化了。简简单单的阐述一个问题多好啊。
博主 就是冲着要出书的方向写的 21 楼 crespo1414 2012-02-24 fenghuazh 写道有点太书面化了。简简单单的阐述一个问题多好啊。
我觉得这样很好
不是教你怎么使用 而是教你这个东西的思想~~
22 楼 inter12 2012-02-24 楼主确实有功底,不仅仅是技术上的功底,同样还有文字功底 23 楼 waainli 2012-03-02 能够了解框架的发展以及内在设计思路最重要。楼主给了我这个初学者很好的学习spring MVC的思路。谢谢。 24 楼 zhulongxing_sz 2012-04-24 在下真得很佩服楼主对 spring mvc 的运行机理的深入理解,讲得真好啊~~~ 25 楼 linghongbo_008 2012-07-26 真的很佩服楼主的技术和文采,除去文采不说,不知道我何时才能达到楼主那样的技术水平 26 楼 xwqiang 2012-08-15 期待next,逻辑性很强!