目录
Spring MVC的九大组件概述
Spring MVC的Servle
Spring MVC中的Servlet一共有三个层次,分别是HttpServletBean、FrameworkServlet和 DispatcherServlet。
(1)HttpServletBean直接继承自Java的HttpServlet,其作用是将Servlet中配置的参数设置到相应的属性
(2)FrameworkServlet初始化了WebApplicationContext
(3)DispatcherServlet初始化了自身的9个组件
Spring MVC的九大组件概述
DispatcherServlet初始化了自身的9个组件。
DispatcherServlet:作为前端控制器,整个流程控制的中心,控制其它组件执行,统一调度,降低组件之间的耦合性,提高每个组件的扩展性。
DispatcherServlet使用了特殊的bean来处理请求、渲染视图等,这些特定的bean是Spring MVC框架的一部分。如果想指定使用哪个特定Bean,可以在web应用上下文WebApplicationContext中简单地配置它们。当然这只是可选的,Spring MVC维护了一个默认的bean列表,如果没有进行特别的配置,框架将会使用默认的Bean。DispatcherServlet都依赖于哪些特殊的bean来进行它的初始化。
bean的类型 | 作用 |
---|---|
HandlerMapping | 处理器映射。它会根据某些规则将进入容器的请求映射到具体的处理器以及一系列前处理器和后处理器(即处理器拦截器)上。具体的规则视HandlerMapping类的实现不同而有所不同。其最常用的一个实现支持你在控制器上添加注解,配置请求路径。当然,也存在其他的实现 |
HandlerAdapter | 处理器适配器。拿到请求所对应的处理器后,适配器将负责去调用该处理器,这使得DispatcherServlet无需关心具体的调用细节。比方说,要调用的是一个基于注解配置的控制器,那么调用前还需要从许多注解中解析出一些相应的信息。因此,HandlerAdapter的主要任务就是对DispatcherServlet屏蔽这些具体的细节 |
HandlerExceptionResolver | 处理器异常解析器。它负责将捕获的异常映射到不同的视图上去,此外还支持更复杂的异常处理代码 |
RequestToViewNameTranslator | ViewName是根据ViewName查找View,但有的Handler处理完后并没有设置View也没有设置ViewName,这时就需要RequestToViewNameTranslator从request中找到默认的View |
ViewResolver | 视图解析器。它负责将一个代表逻辑视图名的字符串(String)映射到实际的视图类型View上 |
LocaleResolver、LocaleContextResolver | 地区解析器、地区上下文解析器。它们负责解析客户端所在的地区信息甚至时区信息,为国际化的视图定制提供了支持 |
ThemeResolver | 主题解析器。它负责解析你web应用中可用的主题,比如,提供一些个性化定制的布局等 |
MultipartResolver | 解析multi-part的传输请求,比如支持通过HTML表单进行的文件上传等 |
FlashMapManager | FlashMap管理器。它能够存储并取回两次请求之间的FlashMap对象。后者可用于在请求之间传递数据,通常是在请求重定向的情境下使用 |
DispatcherServlet维护了一个列表,其中保存了其所依赖的所有bean的默认实现。这个列表保存在包org.springframework.web.servlet下的DispatcherServlet.properties文件中
这些特殊的bean都有一些基本的默认行为。或早或晚,可能需要对它们提供的一些默认配置进行定制。比如说,通常需要配置InternalResourceViewResolver类提供的prefix属性,使其指向视图文件所在的目录。
这里需要理解的一个事情是,一旦在web应用上下文WebApplicationContext中配置了某个特殊bean以后(比如InternalResourceViewResolver),实际上你也覆写了该bean的默认实现。比方说,如果你配置了InternalResourceViewResolver,那么框架就不会再使用beanViewResolver的默认实现
配置好DispatcherServlet以后,开始有请求会经过这个DispatcherServlet。此时,DispatcherServlet会依照以下的次序对请求进行处理:
(1)首先,搜索应用的上下文对象WebApplicationContext并把它作为一个属性(attribute)绑定到该请求上,以便控制器和其他组件能够使用它。属性的键名默认为DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE
(2)将地区(locale)解析器绑定到请求上,以便其他组件在处理请求(渲染视图、准备数据等)时可以获取区域相关的信息。如果你的应用不需要解析区域相关的信息,忽略它即可
(3)将主题(theme)解析器绑定到请求上,以便其他组件(比如视图等)能够了解要渲染哪个主题文件。同样,如果你不需要使用主题相关的特性,忽略它即可
(4)如果你配置了multipart文件处理器,那么框架将查找该文件是不是multipart(分为多个部分连续上传)的。若是,则将该请求包装成一个MultipartHttpServletRequest对象,以便处理链中的其他组件对它做进一步的处理。关于Spring对multipart文件传输处理的支持,读者可以参考Spring MVC 提供multipart(文件上传)支持一小节
(5)为该请求查找一个合适的处理器。如果可以找到对应的处理器,则与该处理器关联的整条执行链(前处理器、后处理器、控制器等)都会被执行,以完成相应模型的准备或视图的渲染
(6)如果处理器返回的是一个模型(model),那么框架将渲染相应的视图。若没有返回任何模型(可能是因为前后的处理器出于某些原因拦截了请求等,比如,安全问题),则框架不会渲染任何视图,此时认为对请求的处理可能已经由处理链完成了
如果在处理请求的过程中抛出了异常,那么上下文WebApplicationContext对象中所定义的异常处理器将会负责捕获这些异常。通过配置你自己的异常处理器,可以定制自己处理异常的方式。
Spring的DispatcherServlet也允许处理器返回一个Servlet API规范中定义的 最后修改时间戳(last-modification-date) 值。决定请求最后修改时间的方式很直接:DispatcherServlet会先查找合适的处理器映射来找到请求对应的处理器,然后检测它是否实现了LastModified 接口。若是,则调用接口的long getLastModified(request)方法,并将该返回值返回给客户端。
可以定制DispatcherServlet的配置,具体的做法,是在web.xml文件中,Servlet的声明元素上添加一些Servlet的初始化参数(通过init-param元素)。该元素可选的参数列表如下:
可选参数 | 解释 |
---|---|
contextClass | 任意实现了WebApplicationContext接口的类。这个类会初始化该servlet所需要用到的上下文对象。默认情况下,框架会使用一个XmlWebApplicationContext对象 |
contextConfigLocation | 一个指定了上下文配置文件路径的字符串,该值会被传入给contextClass所指定的上下文实例对象。该字符串内可以包含多个字符串,字符串之间以逗号分隔,以此支持你进行多个上下文的配置。在多个上下文中重复定义的bean,以最后加载的bean定义为准 |
namespace | WebApplicationContext的命名空间。默认是[servlet-name]-servlet |
1.HandlerMapping:查找Handler
用来查找Handler的。在Spring MVC中会有很多请求,每个请求都需要一个Handler处理,具体接收到一个请求之后使用哪个Handler进行处理呢?这就是HandlerMapping需要做的事
public interface HandlerMapping {
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
2.HandlerAdapter:调用Handler来进行处理
一个适配器。因为Spring MVC中的Handler可以是任意的形式,只要能处理请求就ok,但是Servlet需要的处理方法的结构却是固定的,都是以request和response为参数的方法。如何让固定的Servlet处理方法调用灵活的Handler来进行处理呢?这就是HandlerAdapter要做的事情
任意形式的Handler通过使用适配器,可以“转换”成固定形式,然后交给Servlet来处理。每种Handler都要有对应的HandlerAdapter才能处理请求
public interface HandlerAdapter {
/**
* 判断是否支持传入的handler
*/
boolean supports(Object handler);
/**
* 使用给定的handler处理请求
*/
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
/**
* 返回上次修改时间,可以返回-1表示不支持
*/
long getLastModified(HttpServletRequest request, Object handler);
}
3.HandlerExceptionResolver
其它组件都是用来干活的。在干活的过程中难免会出现问题,出问题后怎么办呢?
这就需要有一个专门的角色对异常情况进行处理,在Spring MVC中就是HandlerExceptionResolver。具体来说,此组件的作用是根据异常设置ModelAndView,之后再交给render方法进行渲染。
HandlerExceptionResolver的接口定义:
public interface HandlerExceptionResolver {
ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);
}
4.ViewResolver
ViewResolver用来将String类型的视图名和Locale解析为View类型的视图。View是用来渲染页面的,也就是将程序返回的参数填入模板里,生成html(也可能是其它类型)文件。这里就有两个关键问题:使用哪个模板?用什么技术(规则)填入参数?
这其实是ViewResolver主要要做的工作,ViewResolver需要找到渲染所用的模板和所用的技术(也就是视图的类型)进行渲染,具体的渲染过程则交由不同的视图自己完成
public interface ViewResolver {
View resolveViewName(String viewName, Locale locale) throws Exception;
}
5.RequestToViewNameTranslator
ViewName是根据ViewName查找View,但有的Handler处理完后并没有设置View也没有设置ViewName,这时就需要RequestToViewNameTranslator从request中找到默认的View了。如何从request中获取ViewName就是RequestToViewNameTranslator要做的事情了。RequestToViewNameTranslator在Spring MVC容器里只可以配置一个,所有request到ViewName的转换规则都要在一个Translator里面全部实现
public interface RequestToViewNameTranslator {
String getViewName(HttpServletRequest request) throws Exception;
}
6.LocaleResolver
解析视图需要两个参数:一是视图名,另一个是Locale。
视图名是处理器返回的,Locale是从哪里来的?这就是LocaleResolver要做的事情。LocaleResolver用于从request解析出Locale,Locale就是zh-cn之类,表示一个区域,有了这个就可以对不同区域的用户显示不同的结果。SpringMVC主要有两个地方用到了Locale:一是ViewResolver视图解析的时候;二是用到国际化资源或者主题的时候
7.ThemeResolver
用于解析主题。Spring MVC中一个主题对应一个properties文件,里面存放着跟当前主题相关的所有资源、如图片、css样式等。Spring MVC的主题也支持国际化,同一个主题不同区域也可以显示不同的风格。Spring MVC中跟主题相关的类有 ThemeResolver、ThemeSource和Theme。主题是通过一系列资源来具体体现的,要得到一个主题的资源,首先要得到资源的名称,这是ThemeResolver的工作。然后通过主题名称找到对应的主题(可以理解为一个配置)文件,这是ThemeSource的工作。最后从主题中获取资源就可以了
8.MultipartResolver
用于处理上传请求。处理方法是将普通的request包装成MultipartHttpServletRequest,后者可以直接调用getFile方法获取File,如果上传多个文件,还可以调用getFileMap得到FileName->File结构的Map。此组件中一共有三个方法,作用分别是判断是不是上传请求,将request包装成MultipartHttpServletRequest、处理完后清理上传过程中产生的临时资源
9.FlashMapManager
用来管理FlashMap的,FlashMap主要用在redirect中传递参数
核心架构的具体流程步骤如下:
(1)首先用户发送请求—>DispatcherServlet
前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制;
(2)DispatcherServlet—>HandlerMapping
HandlerMapping 将会把请求映射为HandlerExecutionChain 对象(包含一个Handler 处理器(页面控制器)对象、多个HandlerInterceptor 拦截器)对象,通过这种策略模式,很容易添加新的映射策略。
(3)DispatcherServlet—>HandlerAdapter
HandlerAdapter 将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器。
(4)HandlerAdapter—>处理器功能处理方法的调用
HandlerAdapter 将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理;并返回一个ModelAndView 对象(包含模型数据、逻辑视图名)
(5)ModelAndView的逻辑视图名—>ViewResolver
ViewResolver 将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术。
(6)View—>渲染
View会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构,因此很容易支持其他视图技术。
(7)返回控制权给DispatcherServlet
由DispatcherServlet返回响应给用户,到此一个流程结束。
下边两个组件通常情况下需要开发:
Handler:处理器,即后端控制器用controller表示。
View:视图,即展示给用户的界面,视图中通常需要标签语言展示模型数据。
Spring MVC的主要组件?
(1)前端控制器 DispatcherServlet(不需要程序员开发)
作用:接收请求、响应结果,相当于转发器,有了DispatcherServlet 就减少了其它组件之间的耦合度。
(2)处理器映射器HandlerMapping(不需要程序员开发)
作用:根据请求的URL来查找Handler
(3)处理器适配器HandlerAdapter
注意:在编写Handler的时候要按照HandlerAdapter要求的规则去编写,这样适配器HandlerAdapter才可以正确的去执行Handler。
(4)处理器Handler(需要程序员开发)
(5)视图解析器 ViewResolver(不需要程序员开发)
作用:进行视图的解析,根据视图逻辑名解析成真正的视图(view)