2.4 详解DispatcherServlet

2.4 详解DispatcherServlet

2.3节中的第一个Spring MVC应用已经成功运行了。那么,前端控制器DispatcherServlet截获请求后做了什么工作呢? DispatcherServlet又是如何分派请求的呢?

initStrategies方法

分析DispatcherServlet的源代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context); //初始化上传文件解析器
initLocaleResolver(context); //初始化本地化解析器
initThemeResolver(context); //初始化主题解析器
initHandlerMappings(context); //初始化处理器映射器,将请求映射到处理器
initHandlerAdapters(context); //初始化处理器适配器
// 初始化处理器异常解析器,如果执行过程中遇到异常将交给`HandlerExceptionResolver`来解析
initHandlerExceptionResolvers(context);
// 初始化请求到视图名称解析器
initRequestToViewNameTranslator(context);
// 初始化视图解析器,通过`ViewResolver`解析逻辑视图名到具体视图实现
initViewResolvers(context);
// 初始化`flash`映射管理器
initFlashMapManager(context);
}

如何下载Spring源码

提示:org/Springframework/web/Servlet/DispatcherServletSpring框架的源代码,读者可在配套资源中找到Spring源代码。

GitHub下载Spring源码

  • GitHub上上下载你想要的版本的zip文件,
  • 解压.
  • 依次进入路径:
    1
    spring-webmvc\src\main\java\org\springframework\web\servlet\
    即可找到DispatcherServlet的源码
    例如,我电脑上的DispatcherServlet路径为:
    1
    G:\Desktop\随书源码\库文件2\spring-framework-5.2.1.RELEASE\spring-webmvc\src\main\java\org\springframework\web\servlet\DispatcherServlet.java
    initstrategies方法将在WebApplicationContext初始化后自动执行,自动扫描上下文的Bean,根据名称或类型匹配的机制査找自定义的组件,如果没有找到则会装配套Spring的默认组件。

    自定义组件

    如果开发者希望使用自定义类型的组件,则只需要在Spring配置文件中配置自定义的Bean组件即可。 Spring MVC如果发现上下文中有用户自定义的组件,就不会使用默认的组件。

    DispatcherServlet装配每种组件的细节

    以下是DispatcherServlet装配每种组件的细节。

    本地化解析器

本地化解析器。只允许一个实例

  • 查找名为localeResolver、类型为.LocaleResolverBean作为该类型组件。
  • 如果没有找到,则使用默认的实现类AcceptHeaderLocaleResolver作为该类型组件。

主题解析器

主题解析器。只允许一个实例

  • 查找名为themeResolver、类型为ThemeResolverBean作为该类型组件。
  • 如果没有找到,则使用默认的实现类FixedThemeResolve作为该类型组件。

处理器映射器

处理器映射器。允许多个实例

  • 如果detectAllHandlerMappings的属性为true(默认为true),则根据类型匹配机制查找上下文以及Spring容器中所有类型为HandlerMappingBean,将它们作为该类型组件。
  • 如果detectAllHandlerMappings的属性为false,则查找名为handlerMapping,类型为HandlerMappingBean作为该类型组件。
  • 如果通过以上两种方式都没有找到,则使用BeanNameUrLHandlerMapping实现类创建该类型的组件。

处理器适配器

处理器适配器。允许多个实例

  • 如果detectAllHandlerAdapters的属性为true(默认为true),则根据类型匹配机制查找上下文以及Spring容器中所有类型为HandlerAdapterBean,将它们作为该类型组件。
  • 如果detectAllHandlerAdapters的属性为false,则查找名为handlerAdapter、类型为HandlerAdapterBean作为该类型组件。
  • 如果通过以上两种方式都没有找到,则使用DispatcherServlet.properties配置文件中指定的三个实现类分别创建一个适配器,并将其添加到适配器列表中。

视图解析器

视图解析器。允许多个实例

  • 如果detectAllViewResolvers的属性为true(默认为true),则根据类型匹配机制查找上下文以及Spring容器中所有类型为ViewResolverBean,将它们作为该类型组件。
  • 如果detectAllViewResolvers的属性为false,则查找名为viewResolvers、类型为ViewResolverBean作为该类型组件。
  • 如果通过以上两种方式都没有找到,则查找DispatcherServlet.properties配置文件中定义的默认实现类InternalResourceViewResolver作为该类型的组件。

文件上传解析器

文件上传解析器。只允许一个实例

  • 查找名为muliipartResolver、类型为MuliipartResolverBean作为该类型组件。
  • 如果用户没有在上下文中显式定义MuliipartResolver类型的组件,则DispatcherServlet将不会加载该类型的组件。

FlashMap映射管理器

FlashMap映射管理器。

  • 查找名为FlashMapManager、类型为SessionFlashMapManagerBean作为该类型组件,用于管理FlashMap,即数据默认存储在HttpSession中。

小结

DispatcherServlet装配的各种组件,

  • 有些只允许一个实例,比如文件上传解析器MuliipartResolver、本地化解析器LocaleResolver等;
  • 有些则允许多个实例,如处理器映射器HandlerMapping、处理器适配器HandlerAdapter等,

读者需要注意这一点。

如果同一类型的组件存在多个,那么它们之间的优先级顺序如何确定呢?因为这些组件都实现了org.springframework.core.Ordered接口,所以可以通过Order属性确定优先级的顺序,值越小的优先级越高。