DispatcherServlet前端控制器
配置
DispatcherServlet充当SpringMVC的前端控制器,整个流程控制的中心,控制其它组件执行,统一调度,降低组件之间的耦合性,提高每个组件的扩展性。与其他Servlet一样,DispatcherServlet必须在Web应用程序的web.xml文件中进行配置
web.xml配置
1 | <!-- springmvc会过滤掉.html的 导致视图解析器无法找到 |
serlvet3.0扩展
在servlet3.0中,可以不使用xml配置servlet,容器会在类路径中查找实现ServletContainerInitializer接口的类,会使用它来配置Servlet容器,在spring中提供了该接口的实现SpringServletContainerInitializer,该实现类会去查找实现WebApplicationInitializer接口的类来完成配置任务,AbstractAnnotationConfigDispatcherServletInitializer就是该接口的基础实现,可以通过继承AbstractAnnotationConfigDispatcherServletInitializer类来进行配置DispatcherServlet
WebApplicationInitializer的作用就类似于web.xml,项目启动时会自动执行onStartup方法
需要实现三个方法
1 | // 将一个或多个路径映射到DispacherServlet |
静态资源请求问题
因为DispatcherServlet的<url-pattern>
配置的是/,针对的是所有请求,对于一些的静态资源(如.js、.css)等也会经过DispatcherServlet,但是DispatcherServlet是处理动态请求的,无法处理静态资源
可以配置<mvc:default-servlet-handler/>
来解决,作用是处理静态资源,会在SpringMVC上下文中定义一个DefaultServletHttpRequestHandle,对进行DispatcherServlet的请求进行筛选,如果发现是没有经过映射的请求,就将请求交给WEB服务器默认的Servlet来处理,否则交由DispatcherServlet来处理
default-servlet-name默认是default,如果不是default需要显式的进行配置(看所使用的web服务器,tomcat是default)
1 | <mvc:default-servlet-handler default-servlet-name="default"/> |
需要注意的是,配置了
<mvc:default-servlet-handler/>
之后,@RequestMapping的映射会失效,需要加上<mvc:annotation-driven/>
配置
源码分析
先看一下DispatcherServlet结构,其本质就是一个Servlet
DispatcherServlet的工作大致可以分为两个部分:一是初始化部分,本质就是一个Servlet,在init方法时会进行初始化,最终调用initStrategies方法;二是对于HTTP请求进行响应,调用doGet和doPost方法,最终调用doDispatch方法
初始化
1 | // DispatcherServlet继承了FrameworkServlet类,FrameworkServlet继承了HttpServletBean类,HttpServletBean继承了HttpServlet,所以DispatcherServlet本质上是一个Servlet |
HttpServletBean的init方法
1 | public final void init() throws ServletException { |
FrameworkServlet的initServletBean方法
1 | protected final void initServletBean() throws ServletException { |
配置刷新WebApplicationContext
1 | protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) { |
onRefresh
用于刷新spring在web功能实现中所必须使用的全局变量
1 | protected void onRefresh(ApplicationContext context) { |
上述默认值是从DispatcherServlet.properties中取的
1 | # 国际化解析器 |
介绍各个组件
LocaleResolver
国际化处理
- AcceptHeaderLocaleResolver 基于URL参数的配置,可以读取url中locale=zh_CN来控制国际化参数
- CookieLocaleResolver 基于cookie的配置,可以通过浏览器的cookie设置获取Locale对象
- SessionLocaleResolver 基于session的配置,可以公国检验session的预置的属性来解析,如果没有则会根据请求头中的accept-language来确定
ThemeResolver
主题处理,根据主题控制网页风格
- FixedThemeResolver 选择一个固定的主题
- CookieThemeResolver 用于实现用户所选的主题,以cookie的形式存放在客户端的机器上
- SessionThemeResolver 用于主题存放在session中
HandlerAdapter
- HttpRequestHandlerAdapter 仅支持HTTP请求处理器的适配,将HTTP请求对象和响应对象传递给HTTP请求处理器的实现,不需要返回值,主要应用在基于HTTP的远程调用实现上
- SimpleControllerHandlerAdapter 将HTTP请求适配到一个控制器的实现进行处理
- AnnotationMethodHandlerAdapter 在3.2被废弃,使用RequestMappingHandlerAdapter,基于注解的实现
HandlerExceptionResolver
进行异常处理
处理请求
请求过来之后进行统一处理,由service()/doGet()/doPost()等方法调用
1 | // doPost -> processRequest -> doService -> doDispatch |
getHandler
1 | protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { |
这里就以RequestMappingHandlerMapping为例
1 | public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { |
ha.handle
通过适配器去调用Handler的实际逻辑,以RequestMappingHandlerAdapter为例
1 | protected ModelAndView handleInternal(HttpServletRequest request, |
invokeHandlerMethod
1 | protected ModelAndView invokeHandlerMethod(HttpServletRequest request, |
processDispatchResult处理请求结果
1 | private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, |
异常解析processHandlerException
1 | protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response, |