在软件开发的中,如果某些特性的使用比较普遍,那么这些特性往往可以作为平台特性来实现,通过对这些平台特性进行有效的封装,使其向其他应用开放。正是如此,Spring由于其IOC、AOP、事务处理、持久化驱动等特点,使得其起到了一个应用平台的作用。Spring MVC是Spring的一个重要的模块,其web应用的实现,是由Spring的来支撑的,Spring MVC的是实现也是依托再Spring平台提供的基础特性的。本文主要是介绍Spring mvc容器初始化的过程,从中可以看出Spring MVC的对于Spring的依赖。
一、从Web应用角度看Spring MVC
在Servlet模型中,请求-响应的实现依赖于两大元素的共同配合:
1. 配置Servlet及其映射关系(在web.xml中)
2. 在Servlet实现类中完成响应逻辑
项目规模扩大之后,请求-响应的映射关系全部定义在web.xml中,将造成web.xml的不断膨胀而变得难以维护。针对这个问题,SpringMVC提出的方案就是:提炼一个核心的Servlet覆盖对所有Http请求的处理。这一被提炼出来的Servlet,通常被我们称之为:核心分发器。在SpringMVC中,核心分发器就是org.springframework.web.servlet.DispatcherServlet。
核心分发器要解决的是下面两个问题:
问题1:核心Servlet应该能够建立起一整套完整的对所有Http请求进行规范化处理的流程。
问题2:核心Servlet应该能够根据一定的规则对不同的Http请求分发到不同的Servlet对象上去进行处理。
针对上面的这个两个问题,SpringMVC的解决方案是:将整个处理流程规范化,并把每一个处理步骤分派到不同的组件中进行处理。
处理流程规范化 :将处理流程划分为若干个步骤(任务),并使用一条明确的逻辑主线将所有的步骤串联起来
处理流程组件化 : 将处理流程中的每一个步骤(任务)都定义为接口,并为每个接口赋予不同的实现模式
处理流程规范化的首要内容就是考虑一个通用的Servlet响应程序大致应该包含的逻辑步骤:
- 对Http请求进行初步处理,查找与之对应的Controller处理类(方法)
- 调用相应的Controller处理类(方法)完成业务逻辑
- 对Controller处理类(方法)调用时可能发生的异常进行处理
- 根据Controller处理类(方法)的调用结果,进行Http响应处理
所谓的组件化,实际上也就是使用编程语言将这些逻辑语义表达出来。在Java语言中,最适合表达逻辑处理语义的语法结构是接口,而接口可以有不同的实现,因此上述的四个流程也就被定义为了四个不同接口,它们分别是:
- HandlerMapping
- HandlerAdapter
- HandlerExceptionResolver
- ViewResolver
二、从Spring角度看Spring MVC
从上面可以看出,组件是核心分发器(DispatchServlet)的核心所在,它们是http请求处理的逻辑载体,DispatcherServlet是逻辑处理的调度中心,组件则是被调度的操作对象。而Spring容器在这里所起到的作用,是协助DispatcherServlet更好地对组件进行管理。
我们知道,SpringMVC的组件是一个个的接口定义,当我们在SpringMVC的核心配置文件中定义一个组件时,使用的却是组件的实现类,用具体的实现类来指定组件的行为模式,不同的实现类代表了不同的行为模式,它们在Spring中是可以共存的。Spring容器对这些实现类进行管理,具体如何使用,由应用程序本身来决定。
上图是Spring官方reference中的一幅图,DispatchServlet对外接收http的请求,而请求的处理的是依靠组件来完成的,组件的接口实现的是依靠Spring IOC容器(WebApplicationContext)来管理。从这个图中我们可以看出,Spring MVC实现web应用是依赖与Spring提供的基础特性(IOC等)。图中的两个WebApplicationContext的区别,留到下面再讲。
三、Spring MVC 入口配置文件web.xml
Spring mvc 有哪些配置文件:
- 入口配置文件:web.xml;由web或应用服务器为每个web项目加载的配置文件。
- 应用上下文:包括web框架特有配置文件:SpringMVC的${dispatcherServletName}-servlet.xml配置文件。和Spring的配置文件applicationContext.xml,applicationContext-*.xml。
遵循servlet规范,Spring MVC的web应用的入口配置文件也是web.xml。web容器的初始化首先是加载web.xml文件,Jetty在启动时首先加载此配置文件,并且对其中定义的listener和servlet等进行相应的加载和初始化。Jetty并不清楚(也不关心)其他配置文件的存在,因此,加载其他配置文件应该是你(框架)的事情。那么怎么加载呢?前面说过Jetty在启动时会自动加载和初始化listener和servlet,那么我们可以自定义一个listener(ContextLoaderListener)或servlet(DispatcherServlet),Jetty会根据web.xml加载和初始化他们,而他们则负责加载相应的配置文件。
在web.xml配置文件中,有两个主要的配置:ContextLoaderListener和DispatcherServlet。同样的关于spring配置文件的相关配置也有两部分:context-param和DispatcherServlet中的init-param。那么,这两部分的分别表示是Spring 容器的初始化和web容器的初始化。Dispatc