Spring MVC工作原理及源码解析(四) ViewResolver实现原理及源码解析
0、ViewResolver原理介绍
- View resolveViewName(String viewName, Locale locale);
该接口的实现类有AbstractCachingViewResolver、BeanNameViewResolver、ContentNegotiatingViewResolver、StandaloneMockMvcBuilder和ViewResolverComposite。

1、AbstractCachingViewResolver:实现带缓存的ViewResolver
public View resolveViewName(String viewName, Locale locale) throws Exception {
// 是否启用缓存,可通过setCache()方法或setCacheLimit()方法开启缓存,是一个ConcurrentHashMap,默认缓存大小1024
if (!this.isCache()) {
return this.createView(viewName, locale);
} else {
// 得到 view 在缓存中的 key 值
Object cacheKey = this.getCacheKey(viewName, locale);
View view = (View)this.viewAccessCache.get(cacheKey);
// 如果没有找到 view 则创建,采用双重校验的方式进行安全创建
if (view == null) {
synchronized(this.viewCreationCache) {
view = (View)this.viewCreationCache.get(cacheKey);
if (view == null) {
// 具体的创建方式由子类实现
view = this.createView(viewName, locale);
if (view == null && this.cacheUnresolved) {
view = UNRESOLVED_VIEW;
}
if (view != null) {
this.viewAccessCache.put(cacheKey, view);
this.viewCreationCache.put(cacheKey, view);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Cached view [" + cacheKey + "]");
}
}
}
}
}
return view != UNRESOLVED_VIEW ? view : null;
}
}
1.1、ResourceBundleViewResolver
使用ResourceBundleViewResolver配置下bean就可以让视图解释器支持解析多种视图,而UrlBasedViewResolver,就只支持解释单一类型的视图。
<bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
<!-- 设定属性文件名为views -->
<property name="basename" value="views"></property>
</bean>
1.2、XmlViewResolver
<bean class="org.springframework.web.servlet.view.XmlViewResolver">
<property name="location">
<value>/WEB-INF/spring-views.xml</value>
</property>
</bean>
1.3、UrlBasedViewResolver
支持解释单一类型的视图。
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="prefix" value="/WEB-INF/" />
<property name="suffix" value=".jsp" />
<property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceView"/>
</bean>
2、其他的 ViewResolver
2.1、BeanNameViewResolver
BeanNameViewResolver 是通过视图名称去容器中获取对应的 view 对象,所以在使用前需要将 view 对象注册到容器中。它没有使用缓存,实现方式如下:
@Override
public View resolveViewName(String viewName, Locale locale) throws BeansException {
ApplicationContext context = getApplicationContext();
// 根据viewName去容器中查找View对象
if (!context.containsBean(viewName)) {
if (logger.isDebugEnabled()) {
logger.debug("No matching bean found for view name '" + viewName + "'");
}
// Allow for ViewResolver chaining...
return null;
}
if (!context.isTypeMatch(viewName, View.class)) {
if (logger.isDebugEnabled()) {
logger.debug("Found matching bean for view name '" + viewName +
"' - to be ignored since it does not implement View");
}
// Since we're looking into the general ApplicationContext here,
// let's accept this as a non-match and allow for chaining as well...
return null;
}
return context.getBean(viewName, View.class);
}
2.2、ContentNegotiatingViewResolver
ContentNegotiatingViewResolver本身不解析解析视图,而是用来整合所有的ViewResolver类,每次请求都会遍历所有的ViewResolver,然后找到最合适的处理View,并将其返回。源码如下:
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes");
// 获取Request的MediaType集合
List<MediaType> requestedMediaTypes = getMediaTypes(((ServletRequestAttributes) attrs).getRequest());
if (requestedMediaTypes != null) {
// 通过遍历ViewResolver,获取所有符合条件的View
List<View> candidateViews = getCandidateViews(viewName, locale, requestedMediaTypes);
// 遍历所有的SmartView,SmartView默认是RedirectView返回
// 否则,根据MediaType最合适的第一个View返回
View bestView = getBestView(candidateViews, requestedMediaTypes, attrs);
if (bestView != null) {
return bestView;
}
}
if (this.useNotAcceptableStatusCode) {
if (logger.isDebugEnabled()) {
logger.debug("No acceptable view found; returning 406 (Not Acceptable) status code");
}
return NOT_ACCEPTABLE_VIEW;
}
else {
logger.debug("No acceptable view found; returning null");
return null;
}
}
2.3、StandaloneMockMvcBuilder
StandaloneMockMvcBuilder主要用于单元测试,代码如下所示:
/**
* A {@link ViewResolver} that always returns same View.(始终返回同一个View,用于单元测试)
*/
private static class StaticViewResolver implements ViewResolver { private final View view; public StaticViewResolver(View view) {
this.view = view;
} @Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
return this.view;
}
}
2.4、ViewResolverComposite
ViewResolverComposite是包含如上各个ViewResolver的组合类,其resolveViewName方法代码如下:
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
for (ViewResolver viewResolver : this.viewResolvers) {
// 生成View对象
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}
return null;
}
Spring MVC工作原理及源码解析(四) ViewResolver实现原理及源码解析的更多相关文章
- Spring MVC工作原理及源码解析(三) HandlerMapping和HandlerAdapter实现原理及源码解析
1.HandlerMapping实现原理及源码解析 在前面讲解Spring MVC工作流程的时候我们说过,前端控制器收到请求后会调⽤处理器映射器(HandlerMapping),处理器映射器根据请求U ...
- Spring MVC工作原理及源码解析(一) MVC原理介绍、与IOC容器整合原理
MVC原理介绍 Spring MVC原理图 上图是Spring MVC工作原理图(图片来自网上搜索),根据上图,我们可以得知Spring MVC的工作流程如下: 1.用户(客户端,即浏览器)发送请求至 ...
- Spring MVC工作原理(好用版)
Spring MVC工作原理 参考: SpringMVC工作原理 - 平凡希 - 博客园https://www.cnblogs.com/xiaoxi/p/6164383.html SpringMVC的 ...
- Zookeeper 源码(四)Zookeeper 服务端源码
Zookeeper 源码(四)Zookeeper 服务端源码 Zookeeper 服务端的启动入口为 QuorumPeerMain public static void main(String[] a ...
- Spring MVC工作原理及源码解析(二)DispatcherServlet实现原理及源码解析
1.DispatcherServlet 处理流程 从上一篇文章中Spring MVC原理图中我们可以看出:DispatcherServlet 在 Spring MVC框架 中处于核心位置,它负责协调和 ...
- Spring MVC工作原理 及注解说明
SpringMVC框架介绍 1) spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面. Spring 框架提供了构建 Web 应用程序的全功 ...
- spring mvc 工作原理
SpringMVC的工作原理图: SpringMVC流程 1. 用户发送请求至前端控制器DispatcherServlet. 2. DispatcherServlet收到请求调用HandlerMa ...
- Spring MVC 工作原理和流程、注解
Spring MVC 是实现MVC设计模式的企业级开发框架,是Spring框架的一个子模块,无需整合,开发起来更加便捷. MVC设计模式 MVC是一种设计模式,它将应用程序分为 Controller. ...
- 浅析Spring MVC工作机制
1.如何使用Spring MVC? 在web.xml中配置一个DispatcherServlet DispatchServlet初始化的时候会去寻找一个在应用程序的WEB-INF目录下的配置文件,命名 ...
随机推荐
- 2019HDU多校第七场 HDU6656 Kejin Player H 【期望递归】
一.题目 Kejin Player H 二.分析 因为在当前等级$i$,如果升级失败可能会退回到原来的某一等级$x$,相当于就是失败的期望就是$E + (Sum[i-1] - Sum[x-1]) + ...
- P1739_表达式括号匹配(JAVA语言)
思路:刚开始想用stack,遇到'('就push,遇到')'就pop,后来发现其实我们只需要用到栈里'('的个数,所以我们用一个变量统计'('的个数就好啦~ 题目描述 假设一个表达式有英文字母(小写) ...
- vps-java环境配置
昨天准备用vps打一台反序列化的机子要java环境,java环境安装了但是javac一直用不了,鼓捣了一段时间把配置文件给搞没了,只好重装vps,找了很多帖子才搞定,为了防止下次继续出现这种情况又要重 ...
- 创建数据库 UTF-8
CREATE DATABASE db_name DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
- 第28 章 : 理解容器运行时接口 CRI
理解容器运行时接口 CRI CRI 是 Kubernetes 体系中跟容器打交道的一个非常重要的部分.本文将主要分享以下三方面的内容: CRI 介绍 CRI 实现 相关工具 CRI 介绍 在 CRI ...
- [状压DP]吃奶酪
吃 奶 酪 吃奶酪 吃奶酪 题目描述 房间里放着 n n n 块奶酪.一只小老鼠要把它们都吃掉,问至少要跑多少距离?老鼠一开始在 ( 0 , 0 ) (0,0) (0,0)点处. 输入 第一行有一个整 ...
- 阅读《构建之法》之FAQ
注:本文档已提交Github,地址是这个 欢迎大家通过PR的方式或者在本博客下留言的方式随时补充意见和建议,我们会持续更新 书中7.2.4的表7-1 MSF团队模型和关键质量目标里面提到的" ...
- 再谈synchronized锁升级
在图文详解Java对象内存布局这篇文章中,在研究对象头时我们了解了synchronized锁升级的过程,由于篇幅有限,对锁升级的过程介绍的比较简略,本文在上一篇的基础上,来详细研究一下锁升级的过程以及 ...
- 201871030118-雷云云 实验三 结对项目—《D{0-1}KP 实例数据集算法实验平台》项目报告
项目 内容 课程班级博客 班级链接 这个作业要求链接 作业链接 我的课程学习目标 (1)体验软件项目开发中的两人合作,练习结对编程(2)掌握Github协作开发程序的操作方法(3)学习遗传算法 这个作 ...
- HarmonyOS三方件开发指南(17)-BottomNavigationBar
目录: 1.引言 2.功能介绍 3.BottomNavigationBar使用指南 4.BottomNavigationBar开发指南 5.<HarmonyOS三方件开发指南>文章合集 引 ...