前言
ViewResolver也就是视图解析器,他将是我们《探索SpringMVC》系列要介绍的最后一个常用的组件。其他组件:MultipartResolver、LocaleResolver、ThemeResolver、RequestToViewNameTranslator、FlashMapManager,相对简单,大家可以自行了解。
ViewResolver
我们知道视图技术有很多种,例如:JSP、FreeMarker、Thymeleaf等。如果直接操作这些技术,那简直不要太糟糕。为了统一操作,SpringMVC抽象出来两个接口:ViewResolver和View。任何视图技术都需要实现这两个接口。
Spring源码中的定义
- ViewResolver,即视图解析器,可以通过将viewName解析为View。
- View,即视图,是Web交互的MVC的View。他的实现者负责渲染内容、暴露Model。(所谓暴露model,其实就是把model数据在页面中展示)
从上述定义,视图解析器需要创建View。而这意味着两个重要使命实例化和初始化。实例化,当然是创建对应的View实现对象。而初始化则负责将View与对应的实现技术进行绑定/衔接。
与视图技术的衔接
前面我们知道View才是真正渲染页面内容的,这意味着View才是视图技术的真正操作者。因此必须通过某种手段获得响应的配置或者重要的组件。而Spring提供的是WebApplicationObjectSupport
。不管是ViewResolver,还是View都是基于该抽象类来实现获取ApplicationContext。
Spring的设计
为了便于各个视图技术厂商对接,Spring实际上构建了一套完整的体系(一系列抽象实现类),按需实现。
这里重点提一下
UrlBaseViewResolver#applyLifecycleMethods
这个方法是初始化View的关键方法,他通过ApplicationContext获取到AutowireCapableBeanFactory,并且直接调用其initializeBean方法进行初始化。而该方法就是我们bean生命周期中的关键方法,包括:Aware接口、BeanPostProcessor、InitializingBean都是由他负责。
FreeMarker的实现
前面我们说了,WebApplicationObjectSupport
是重要的初始化接口。同样我们也说,是按需实现。
FreeMarkerViewResolver
从上面的类图看,FreeMarkerViewResolver似乎并没有使用到这个接口,但是其父类UrlBaseViewResolver使用到了。UrlBaseViewResolver通过WebApplicationObjectSupport
才能获取到ApplicationContext。才有了后面对FreeMarkerView的初始化。
FreeMarkerView
通过该WebApplicationObjectSupport
实现了与FreeMarker的衔接。
重点方法:
FreeMarkerView#initServletContext
这个方法实际上是Aware接口扩展过来的,因此会被前面说的UrlBaseViewResolver#applyLifecycleMethods
调用到。这里会通过ApplicationContext获取到FreeMarkerConfig。该类是SpringMVC与Freemarker衔接的类,他会持有FreeMarker的Configuration对象。通过Configuration对象,就能获得FreeMarker的Template类。FreeMarkerView#buildTemplateModel
该方法将Model转换为FreeMarker要求的数据格式。FreeMarkerView#processTemplate
该方法则是实际调用FreeMarker的Template,通过HttpServletResponse将视图渲染并响应了。
想看源码的同学,这里送一张简化版调用流程图
注意,该图不涉及分支流程,例如:缓存逻辑、重定向逻辑。
总结
- Spring为了统一视图技术的操作,抽象了ViewResolver和View。并提供了许多抽象接口,以便不同的视图技术进行实现。
- UrlBaseViewResolver通过
WebApplicationObjectSupport
获取到ApplicationContext对AbstractUrlBasedView进行初始化。AbstractUrlBasedView则通过InitializingBean实现对View的url进行校验。 - FreeMarkerView通过
WebApplicationObjectSupport
从容器中获取FreeMarkerConfig,实现与FreeMarker的衔接。
后记
ViewResolver相对简单。但我们重点要学会设计思想。SpringMVC设计了一层中间层,做了一层接口转换,换取统一接口、统一操作的便利,以及更多的扩展可能。
下一次,我们终于回到了DispatcherServlet了。忘记的同学,可以回去看看。
上一篇:
探索SpringMVC-组件之HandlerExceptionResolver
第一篇:
探索SpringMVC-web上下文