在请求静态资源文件的时候,Spring内部是如何实现的呢?之前对这个问题,有疑问,但如果是自己处理静态的资源都是统一的使用IOUtils.copy(input,output)中去,想了解下Spring内部是如何做的。
带着疑问阅读下源码,果不其然,一起看下
分析
之前我们提到了DispatcherServlet的doDispatcher大致流程,这次我们以静态资源文件为例,再看下。
- 在dispatcher-servlet.xml配置文件里面,配置静态资源的路径。然后在js目录下新建一个index.js文件
<mvc:resources mapping="/js/**" location="/js/" />
- 启动项目,调试在getHandler这一步,我们可以看到配置的HandlerMappings,其中SimpleUrlHandlerMapping是我们在xml配置文件中配置的,我们写几个resource的映射,就有几个SimpleUrlHandlerMapping对象。
像RequestMappingHandlerMapping,根据请求的路径获取Bean对应的HandlerMethod,然后封装。
BeanNameUrlHandlerMapping再调试的时候还未遇到。
SimpleUrlHandlerMapping根据我们在配置文件里面的定义,可以看到获取到对应的ResourceHttpRequestHandler.
-
获取静态资源的HandlerAdpater. 这些都是之前分析doDispatch提到的
三个不同的Adpater内部实现的support机制不同,如果support返回true则获得对应的Adapter.
支持ResourceHttpRequestHandler的Handler只有HttpRequestHandlerAdapter,看他们的名字差不多就可以对应上来。
- 拦截器预处理,不多说了
-
进行处理HanderAdapter.handler(request,response,handler)
静态资源的HandlerAdpater处理很少,直接交给Handler进行的处理,没有额外的操作。
handleRequest内部处理如下:
- getResource获取路径对应的静态资源,文件
- 检查请求是否合法
- 判断是否要加cache的Http Header
- 根据Http是否有Range头部,不管有无,都通过StreamUtils进行流拷贝。中间又利用到ResourceHttpMessageConverter.
HttpMessageConterver可以转换Request和Response的一些内容,细节以后再讨论
将静态资源文件通过流的方式输出到输出流之后,ModelAndView值为null,所以不会对视图进行处理
Handler的拦截器进行postHandler处理,之前提到过,这里不多说了。
处理分发结果,errorView,exception,modelandview都为null,也就是都不处理,最后进行拦截器的triggerAfterCompletion操作
进行最后的清理工作,请求完成
回顾
如果明白doDispatcher的流程之后,再去看静态资源的处理,就简单很多,因为服务静态资源也是doDispatch的一部分。
服务静态资源简单来说:
首先,根据我们定义的resorce映射,内部会创建SimpleUrlHandler,在获取到Handler之后,静态资源的HandlerAdpater也比较简单,它的Adpater仍然是把操作交给Handler处理。
Handler内部因为是静态资源,没有太多的逻辑操作,只是对Http的请求头做一些判断,最后都是由ResourceHttpMessageConverter将资源通过流的方式输出到Resouce.
后续基本上只是拦截器稍微工作一下,其余基本上都是跳过的操作
总结
Spring MVC对静态资源的处理,相对简单一些。