首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

Spring深度探险3

2012-10-27 
Spring深度探险三声明:本文来自于http://downpour.iteye.com/blog/1341459?在上一篇文章中,我们给出了构成

Spring深度探险三

声明:本文来自于http://downpour.iteye.com/blog/1341459

?

在上一篇文章中,我们给出了构成SpringMVC应用程序的三要素以及三要素的设计过程。让我们来归纳一下整个设计过程中的一些要点:

SpringMVC将Http处理流程抽象为一个又一个处理单元SpringMVC定义了一系列组件(接口)与所有的处理单元对应起来SpringMVC由DispatcherServlet贯穿始终,并将所有的组件串联起来

在整个过程中,组件和DispatcherServlet总是维持着一个相互支撑的关系:

DispatcherServlet —— 串联起整个逻辑主线,是整个框架的心脏组件 —— 逻辑处理单元的程序化表示,起到承上启下的作用,是SpringMVC行为模式的实际承载者

在本系列接下来的两篇文章中,我们将分别讨论DispatcherServlet和组件的相关内容。本文讨论DispatcherServlet,而下一篇则重点分析组件。

有关DispatcherServlet,我们想从构成DispatcherServlet的体系结构入手,再根据不同的逻辑主线分别加以分析,希望能够帮助读者整理出学习SpringMVC核心类的思路。

DispatcherServlet的体系结构

通过不同的角度来观察DispatcherServlet会得到不同的结论。我们在这里选取了三个不同的角度:运行特性、继承结构和数据结构。

【运行主线】

从DispatcherServlet所实现的接口来看,DispatcherServlet的核心本质:是一个Servlet。这个结论似乎很幼稚,不过这个幼稚的结论却蕴含了一个对整个框架都至关重要的内在原则:Servlet可以根据其特性进行运行主线的划分

根据Servlet规范的定义,Servlet中的两大核心方法init方法和service方法,它们的运行时间和触发条件都截然不同:

1. init方法

在整个系统启动时运行,且只运行一次。因此,在init方法中我们往往会对整个应用程序进行初始化操作。这些初始化操作可能包括对容器(WebApplicationContext)的初始化、组件和外部资源的初始化等等。

2. service方法

在整个系统运行的过程中处于侦听模式,侦听并处理所有的Web请求。因此,在service及其相关方法中,我们看到的则是对Http请求的处理流程。

因而在这里,Servlet的这一特性就被SpringMVC用于对不同的逻辑职责加以划分,从而形成两条互不相关的逻辑运行主线:

初始化主线 —— 负责对SpringMVC的运行要素进行初始化Http请求处理主线 —— 负责对SpringMVC中的组件进行逻辑调度完成对Http请求的处理

对于一个MVC框架而言,运行主线的划分非常重要。因为只有弄清楚不同的运行主线,我们才能针对不同的运行主线采取不同的研究策略。而我们在这个系列中的绝大多数分析的切入点,也是围绕着不同的运行主线进行的。

:SpringMVC运行主线的划分依据是Servlet对象中不同方法的生命周期。事实上,几乎所有的MVC都是以此为依据来进行运行主线的划分。这进一步可以证明所有的MVC框架的核心基础还是Servlet规范,而设计理念的差异也导致了不同的框架走向了完全不同的发展道路。

【继承结构】

除了运行主线的划分以外,我们再关注一下DispatcherServlet的继承结构:

Spring深度探险3

在这个继承结构中,我们可以看到DispatcherServlet在其继承树中包含了2个Spring的支持类:HttpServletBean和FrameworkServlet。我们分别来讨论一下这两个Spring的支持类在这里所起到的作用。

HttpServletBean是Spring对于Servlet最低层次的抽象。在这一层抽象中,Spring会将这个Servlet视作是一个Spring的bean,并将init-param中的值作为bean的属性注入进来:



        我们可以把在上面这张图中所构成DispatcherServlet的数据结构主要分为两类(我们在这里用一根分割线将其分割开来):

        配置参数 —— 控制SpringMVC组件的初始化行为方式核心组件 —— SpringMVC的核心逻辑处理组件

        可以看到,这两类数据结构都与SpringMVC中的核心要素组件有关。因此,我们可以得出这样一个结论:



        :在这幅图中,我们除了看到在图的左半边DispatcherServlet、组件和容器这三者之间的调用关系以外,还可以看到SpringMVC的运行体系与其它运行体系之间存在着关系。有关这一点,我们在之后的讨论中会详细展开。

        既然是三个元素之间的关系表述,我们必须以两两关系的形式进行归纳:

        DispatcherServlet - 容器 —— DispatcherServlet对容器进行初始化容器 - 组件 —— 容器对组件进行全局管理DispatcherServlet - 组件 —— DispatcherServlet对组件进行逻辑调用

        值得注意的是,在上面这幅图中,三大元素之间的两两关系其实表现得并不明显,尤其是“容器 - 组件”和“DispatcherServlet - 组件”之间的关系。这主要是由于Spring官方reference所给出的这幅图是一个静态的关系表述,如果从动态的观点来对整个过程加以审视,我们就不得不将SpringMVC的运行体系与之前所提到的运行主线联系在一起,看看这些元素在不同的逻辑主线中所起到的作用。

        接下来,我们就分别看看DispatcherServlet的两条运行主线。

        DispatcherServlet的初始化主线

        对于DispatcherServlet的初始化主线,我们首先应该明确几个基本观点:

        初始化主线的驱动要素 —— servlet中的init方法初始化主线的执行次序 —— HttpServletBean -> FrameworkServlet -> DispatcherServlet初始化主线的操作对象 —— Spring容器(WebApplicationContext)和组件

        这三个基本观点,可以说是我们对之前所有讨论的一个小结。明确了这些内容,我们就可以更加深入地看看DispatcherServlet初始化主线的过程:

        Spring深度探险3

        在这幅图中,我们站在一个动态的角度将DispatcherServlet、容器(WebApplicationContext)和组件这三者之间的关系表述出来,同时给出了这三者之间的运行顺序和逻辑过程。读者或许对其中的绝大多数细节还很陌生,甚至有一种无从下手的感觉。这没有关系,大家可以首先抓住图中的执行线,回忆一下之前有关DispatcherServlet的继承结构和数据结构的内容。接下来,我们就图中的内容逐一进行解释。

        【WebApplicationContext的初始化】

        之前我们讨论了DispatcherServlet对于WebApplicationContext的初始化是在FrameworkServlet中完成的,不过我们并没有细究其中的细节。在默认情况下,这个初始化过程是由web.xml中的入口程序配置所驱动的:



            所有的这些配置选项,实际上都是为了让DispatcherServlet对WebApplicationContext的初始化过程显得更加自然。不过这只是完成了容器(WebApplicationContext)的构建工作,那么容器所管理的那些组件,又是如何进行初始化的呢?



                          我们可以观察一下DispatcherServlet.properties的内容:

                          引用# Default implementation classes for DispatcherServlet's strategy interfaces.
                          # Used as fallback when no matching beans are found in the DispatcherServlet context.
                          # Not meant to be customized by application developers.

                          org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

                          org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver

                          org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
                          org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping

                          org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
                          org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
                          org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter

                          org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\
                          org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
                          org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

                          org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

                          org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

                          org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.DefaultFlashMapManager



                          结合刚才initHandlerMappings的源码,我们可以发现如果没有开启detectAllHandlerAdapters选项或者根据HANDLER_ADAPTER_BEAN_NAME的名称没有找到相应的组件实现类,就会使用DispatcherServlet.properties文件中对于HandlerMapping接口的实现来进行组件默认行为的初始化。

                          由此可见,DispatcherServlet.properties中所指定的所有接口的实现方式在Spring的容器WebApplicationContext中总有相应的定义。这一点,我们在组件的讨论中还会详谈。

                          这个部分我们的侧重点是图中DispatcherServlet与容器之间的关系。读者需要理解的是图中为什么会有两份组件定义,它们之间的区别在哪里,以及DispatcherServlet在容器中查找组件的三种策略。

                          小结

                          在本文中,我们对SpringMVC的核心类:DispatcherServlet进行了一番梳理。也对整个SpringMVC的两条主线之一的初始化主线做了详细的分析。

                          对于DispatcherServlet而言,重要的其实并不是这个类中的代码和逻辑,而是应该掌握这个类在整个框架中的作用以及与SpringMVC中其他要素的关系。

                          对于初始化主线而言,核心其实仅仅在于那张笔者为大家精心打造的图。读者只要掌握了这张图,相信对整个SpringMVC的初始化过程会有一个全新的认识。

热点排行