SpringMVC主要做了什么
传统的Servlet模型
在Servlet模型中,请求-响应的实现依赖于两大元素的共同配合:
- 配置Servlet及其映射关系(在web.xml中)
- 在Servlet实现类中完成响应逻辑
使用这个模型时,会有以下问题:
- 项目规模扩大之后,请求-响应的映射关系全部定义在web.xml中,将造成web.xml的不断膨胀而变得难以维护
- 开发效率不高,一些共性的东西需要自己提炼,例如参数的映射、http头信息以及实体信息的良好封装等
SpringMVC做了什么
SpringMVC提出了一个方案:提炼一个核心的Servlet覆盖对所有Http请求的处理。这一被提炼出来的Servlet,通常被我们称之为:核心分发器。在SpringMVC中,核心分发器就是org.springframework.web.servlet.DispatcherServlet。
核心分发器要解决的是下面两个问题:
- 核心Servlet应该能够建立起一整套完整的对所有Http请求进行规范化处理的流程
- 核心Servlet应该能够根据一定的规则对不同的Http请求分发到不同的Servlet对象上去进行处理
针对上面的这个两个问题,SpringMVC的解决方案是:将整个处理流程规范化,并把每一个处理步骤分派到不同的组件中进行处理。
- 处理流程规范化 :将处理流程划分为若干个步骤(任务),并使用一条明确的逻辑主线将所有的步骤串联起来
- 处理流程组件化 : 将处理流程中的每一个步骤(任务)都定义为接口,并为每个接口赋予不同的实现模式
处理流程规范化的首要内容就是考虑一个通用的Servlet响应程序大致应该包含的逻辑步骤:
- 对Http请求进行初步处理,查找与之对应的Controller处理类(方法)
- 调用相应的Controller处理类(方法)完成业务逻辑
- 对Controller处理类(方法)调用时可能发生的异常进行处理
- 根据Controller处理类(方法)的调用结果,进行Http响应处理
所谓的组件化,实际上也就是使用编程语言将这些逻辑语义表达出来。在Java语言中,最适合表达逻辑处理语义的语法结构是接口,而接口可以有不同的实现,因此上述的四个流程也就被定义为了四个不同接口,它们分别是:
- HandlerMapping
- HandlerAdapter
- HandlerExceptionResolver
- ViewResolver
SpringMVC上下文层次
上面的介绍中,DispatcherServlet无疑是最重要的核心组件,是逻辑处理的调度中心,组件则是被调度的操作对象。而Spring容器在这里所起到的作用,是协助DispatcherServlet更好地对组件进行管理。
DispatcherServlet需要一个WebApplicationContext,它是普通ApplicationContext的扩展,用于自己的配置。 WebApplicationContext有一个指向它与之关联的ServletContext和Servlet的链接。 它还绑定到ServletContext,以便应用程序可以使用RequestContextUtils上的静态方法来查找WebApplicationContext。
对于许多具有单个WebApplicationContext的应用程序而言,这很简单。 也可以有一个上下文层次结构,其中一个根WebApplicationContext在多个DispatcherServlet(或其他Servlet)实例之间共享,每个实例都有自己的子WebApplicationContext配置。
根WebApplicationContext通常包含基础bean,例如需要跨多个Servlet实例共享的数据存储和一些业务服务。 这些bean是有效继承的,可以在特定于Servlet的子WebApplicationContext中重新声明,该子WebApplicationContext通常包含给定Servlet本地的bean:
配置DispatcherServlet和上下文
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
分解上面的配置:
配置了根上下文的的配置文件的位置
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring.xml</param-value>
</context-param>
声明一个listener,用来初始化根上下文
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
配置DispatcherServlet,并指定该DispatcherServlet的上下文的配置文件的位置
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--指定当期DispatcherServlet的上下文配置文件的位置-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>