Springboot配置多个视图解析器,关于ViewResolver内容协商原理
近期看了点Spring boot的框架源码,研究了一下WEB Mvc的视图解析器,记录一下,以备以后查阅.如果认知错误,还请小伙伴指教讨论.
-
几个核心的类
DispatherServlet(前端控制器)、ViewResolver(视图解析器)、View(视图类) -
以下使用两个视图解析器作为例子,比较好区别
其一:ThymeleafViewResolver
另一:InternalResourceViewResolver(系统默认实现)
在WebMvcAutoConfiguration 自动注入
1.DispatcherServlet在选择视图解析器的时候,以优先级为处理原则,此优先级是根据该ViewResolver实现Ordered接口或者使用@Order注解赋值,数字最小优先级越高为原则.
2.通过判断,返回一个具体的View类,最终通过3、4步骤渲染成HTML或者是XML等视图内容.
ViewResolver视图解析器在DispatcherServlet解析
源码类DispatcherServlet
- 关于ViewResovlers排序
系统通过下图该方法,对于视图解析器进行排序sort,排序的原则还是按照Order的大小(ps viewResolvers是一个List集合) - 关于匹配View对象的方法,遍历viewResolvers,匹配到第一个View对象,则返回.
ViewResolver内容协商原理
代码入口:
多视图产生的常见错误(当我们配置多个视图解析器时,出现只支持一种视图解析器器,其他类型产生404)
在工作中,我们发现,如果我们新建了一个视图解析器,这里我使用ThymeleafViewResolver作为例子,我们会发现,如果该视图解析器只配置了支持HTML的解析,在我们访问JSP页面时候,会出现404的错误.
前面我们已经知道,视图解析器在解析的时候,是根据Order的大小来判断优先级.
上面这个错误,我们如果尝试以源码的角度来解析,这是因为我们这时候系统出现了两个视图解析器,而优先级ThymeleafViewResolver比InternalResourceViewResolver高,这里我们可以看一下源码:
- ThymeleafAutoConfiguration
我们可以很清楚的看出来ThymeleafViewResolver的Order为 Ordered.LOWEST_PRECEDENCE - 5 - InternalResourceViewResolver
果然经过层层跳转,发现自动注入的InternalResourceViewResolver的优先级为最低级.注意:这里指的是自动注入,就是在我们不经过任何改造的情况下,是属于最低级.
下图是通过debug的方式,看到真实的排序是跟我们看到的源码是一致的.
该错误的解决思路
1.可以通过自定义视图解析器,设置其优先级高于 ThymeleafAutoConfiguration :Ordered.LOWEST_PRECEDENCE - 5.
通过debug的方式,看到此时自定义的InternalResourceViewResolver已经是优先级最高.
2.其实到这里,还是不能处理兼容处理多种格式,例如同时兼容HTML和XML,这里还是同样用源码的角度来解释这个现象,首先我们需要注意的是ContentNegotiatingViewResolver这个视图解析器,其实这个视图解析器就是一个视图内容的协商,而且这个视图解析器如上图所示,它的优先级是最高的,这一点可以去看它的Order.
先说它的作用,它其实是去关联除了自己以外的所有视图解析器,可以通过它来实现一种资源返回多种形式.
两个比较重要的参数:
- favorPathExtension:是否支持扩展名,默认为true(支持),扩展名指的xxx.json、xxx.xml等形式
- favorParameter:是否启用参数支持,默认为true(支持),即xxx?format=json、xxx?format=xml等形式,这里的参数名默认为format,可以通过配置改变。
说完该视图解析器的简单介绍,说说为什么不能实现多种解析的兼容,如下图可以看到,默认的处理contentType都为text/html,所以当匹配到优先级为最先时,系统就会直接交给这个视图处理器处理,所以会出现支持不了的情况.
这里通过设置contenType来区别各个匹配器,这里我设置了以text/xml,然后去访问,可以达到不同的效果
实验结果
- 实验一
- 用text/html显示html页面.
- 用text/xml显示html页面.
实验二,
使用format参数,也可以显示不同的页面,使用不同的处理器