先给出一个基本的配置(web.xml中配置),后面再对这个配置做详细说明。
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/springmvc-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
DispatcherServlet,本质上就是一个Servlet。所以,它的基本配置,就如同配置一个Servlet一样,即:所有以/app开头的请求都会进入上面配置的Servlet中。当然,该Servlet接收到这个请求之后,需要哪些类来处理相应的业务,这就是框架做的了,后面再分析。
因此:除了Spring MVC提供的DispatcherServlet外,还可以配置自己写的一些Servlet。同样,也可以配置多个DispatcherServlet。如果是配置多个DispatcherServlet,那么肯定每个DispatcherServlet处理的业务是不一样的,因此需要设置一些值来保证每个DispatcherServlet的特殊化。
所以,可以这么理解DispatcherServlet,他就是一个Servlet,里面有一些属性,这些属性可以由用户自己设定相应的值(当然,我们在使用的时候,不配置这些值也是可以的,框架会自动设置这些值的。)
WebApplicationContext
在每个DispatcherServlet中都持有一个上下文对象WebApplicationContext,WebApplicationContext就是一个IoC容器,里面可以存放一些框架需要的和我们自己定义的bean。如何配置这个上下文呢?在开头的配置中:
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/springmvc-servlet.xml</param-value>
</init-param>
这个配置的意思就是使用我们制定的WEB-INF目录下的springmvc-servlet.xml配置文件来初始化上下文对象WebApplicationContext。如果没有这个配置,WebApplicationContext也会被初始化,因为Spring MVC有一个默认的约定:默认情况下,DispatcherServlet会加载WEB-INF/[DispatcherServlet的Servlet名字]-servlet.xml(例如,例子中的默认的名字就是:springmvc-servlet.xml)配置文件作为WebApplicationContext的初始化配置。
如果需要获取WebApplicationContext上下文,可以通过RequestContextUtils工具类中的静态方法来拿到这个web应用的上下文WebApplicationContext。
更多参数
在配置WebApplicationContext上下文的时候,init-param中还可以配置以下值:
可选参数 | 说明 |
---|---|
contextClass | 可以是任意一个实现了WebApplicationContext接口的类。这个类会初始化该servlet所需要用到的上下文对象。默认情况下,框架会使用一个XmlWebApplicationContext对象。 |
contextConfigLocation | 一个指定了上下文配置文件路径的字符串,该值会被传入给contextClass所指定的上下文实例对象。该字符串内可以包含多个字符串,以逗号分隔,以此支持多个上下文的配置。在多个上下文中重复定义的bean,后面的bean或覆盖之前重复bean |
namespace | WebApplicationContext的命名空间。默认是[servlet-name]-servlet |
WebApplicationContext中的特殊bean
之前讲到,在WebApplicationContext中有一些默认的bean,那这些bean是什么呢?有什么作用?
这些特殊的bean,可以在org.springframework.web.servlet包下(DispatcherServlet同级),找到一个名为DispatcherServlet.properties的配置文件,里面配置了一些默认的特殊bean,这些bean默认情况下会被注入到WebApplicationContext上下文,这些bean的含义是:
bean | 作用 |
---|---|
HandlerMapping | 处理器映射。它会根据某些规则将进入容器的请求映射到具体的处理器以及一系列前处理器和后处理器(即处理器拦截器)上。具体的规则视HandlerMapping类的实现不同而有所不同。其最常用的一个实现支持你在控制器上添加注解,配置请求路径。 有两个重要的实现类:RequestMappingHandlerMapping和SimpleUrlHandlerMapping。 |
HandlerAdapter | 处理器适配器。拿到请求所对应的处理器后,适配器将负责去调用该处理器,这使得DispatcherServlet无需关心具体的调用细节。 |
HandlerExceptionResolver | 处理器异常解析器。它负责将捕获的异常映射到不同的视图上去,此外还支持更复杂的异常处理代码。 |
ViewResolver | 视图解析器。它负责将一个代表逻辑视图名的字符串(String)映射到实际的视图类型View上。 |
LocaleResolver & LocaleContextResolver | 地区解析器 和 地区上下文解析器。它们负责解析客户端所在的地区信息甚至时区信息,为国际化的视图定制提供了支持。 |
ThemeResolver | 主题解析器。它负责解析你web应用中可用的主题,比如,提供一些个性化定制的布局等。 |
MultipartResolver | 解析multi-part的传输请求,比如支持通过HTML表单进行的文件上传等。 |
FlashMapManager | FlashMap管理器。它能够存储并取回两次请求之间的FlashMap对象。后者可用于在请求之间传递数据,通常是在请求重定向的情境下使用。 |
这些默认被加载的bean,是有很大的作用的,是核心中的核心。前面有将到,相同的bean,如果被重复定义,那么后者会覆盖前者。而这些默认的bean,是先被加载的,也就是说,我们可以定义一个相同的bean(比如,直接使用默认的bean,然后自己改一些配置参数),来定制化自己的实现,例如,定制化视图解析:
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/views/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
再次强调,这些默认的bean要记清楚,不理解没关系(在之后的文章中会继续分析这些bean),只要当发现默认的实现不能满足你的需求的时候,能想到定制化这些bean,那么到时偶再做功课都还来得及。
Spring MVC的请求处理流程
- 将WebApplicationContext上下文绑定到请求上,这样控制器和其他的组件bean就可以使用它了。该属性的键名为:DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE
- 将地区解析器(LocaleResolver)绑定到请求上,以便其他组件在处理请求(渲染视图、准备数据等)时可以获取区域相关的信息。
- 将主题解析器(ThemeResolver)绑定到请求上,以便其他组件(比如视图等)能够了解要渲染哪个主题文件。
- 如果你配置了multipart文件处理器,那么框架将查找该文件是不是multipart(分为多个部分连续上传)的。若是,则将该请求包装成一个MultipartHttpServletRequest对象,以便处理链中的其他组件对它做进一步的处理。
- 通过处理器映射(HandlerMapping),为该请求查找一个合适的处理器。如果可以找到对应的处理器,则与该处理器关联的整条执行链(前置处理器、后置处理器、控制器等)都会被执行,以完成相应模型的准备或视图的渲染。
- 如果处理器返回的是一个模型(model),那么框架将渲染相应的视图。若没有返回任何模型(可能是因为前后的处理器出于某些原因拦截了请求等,比如,安全问题),则框架不会渲染任何视图,此时认为对请求的处理可能已经由处理链完成了。
最后需要说明的一点是,如果在整个过程中,出现了异常,则上下文WebApplicationContext中绑定的异常处理解析器(HandlerExceptionResolver)就会起作用,它会捕获这些异常。通常而言,都是通过配置自己的异常处理器来将不同的异常定制化处理(比如跳转到不同的错误页面等)。