博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SpringMVC之源码分析--ViewResolver(五)
阅读量:6242 次
发布时间:2019-06-22

本文共 7278 字,大约阅读时间需要 24 分钟。

概述

通过上几篇的学习,我们分析了并试验了ViewResolverComposite、BeanNameViewResolver和ContentNegotiatingViewResolver,这三个类都直接实现ViewResolver接口。Spring MVC提供了很多的ViewResolver实现,本章我们继续分析比较常用的几个视图解析器。

本系列文章是基于Spring5.0.5RELEASE。

AbstractCachingViewResolver

AbstractCachingViewResolver实现ViewResolver接口的抽象类,从类名可知,该类具有缓存功能,即缓存解析过的视图View对象,后续需要视图解析时,会先从缓存中查找,如果找到对应的视图就直接返回,如果未找到就创建一个视图对象放入缓存Map中,并返回创建对象。从其实现原理上来看,此类视图解析器的性能是最佳的。

public abstract class AbstractCachingViewResolver extends WebApplicationObjectSupport implements ViewResolver {    /** 缓存视图map的初始大小 */    public static final int DEFAULT_CACHE_LIMIT = 1024;        /** 最大缓存数量 */    private volatile int cacheLimit = DEFAULT_CACHE_LIMIT;    /** 解析过的View缓存容器,key是逻辑视图名,value是视图View对象 */    private final Map
viewAccessCache = new ConcurrentHashMap<>(DEFAULT_CACHE_LIMIT); /** 存储所有创建过的视图,本容器里的内容大于等于viewAccessCache中的内容 key是逻辑视图名,value是视图View对象 */ private final Map
viewCreationCache = new LinkedHashMap
(DEFAULT_CACHE_LIMIT, 0.75f, true) { @Override protected boolean removeEldestEntry(Map.Entry
eldest) { // 本容器内数量大于缓存数量时,移除最老的对象 if (size() > getCacheLimit()) { // 移除缓存容器中最老的View对象 viewAccessCache.remove(eldest.getKey()); return true; } else { return false; } } }; /** 实现ViewResolver接口resolveViewName方法 */ @Override @Nullable public View resolveViewName(String viewName, Locale locale) throws Exception { // 缓存开关(默认开启)。通过属性cacheLimit的值控制,大于0开启缓存,小于0关闭缓存 if (!isCache()) { return createView(viewName, locale); } else { // 获取逻辑视图名称 Object cacheKey = getCacheKey(viewName, locale); // 从缓存容器中查找缓存过的视图对象 View view = this.viewAccessCache.get(cacheKey); // 缓存中未找到 if (view == null) { synchronized (this.viewCreationCache) { // 从创建过的视图容器中查找 view = this.viewCreationCache.get(cacheKey); if (view == null) { // 调用子类创建视图View对象 view = 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 (logger.isTraceEnabled()) { logger.trace("Cached view [" + cacheKey + "]"); } } } } } // 返回View对象 return (view != UNRESOLVED_VIEW ? view : null); } } ... ...}

以上是AbstractCachingViewResolver的核心代码。简单说,本类就是实现了视图解析的缓存功能。

UrlBasedViewResolver

该类是ViewResolver接口的一种实现,并继承了AbstractCachingViewResolver抽象类,通过指定prefix前缀和suffix后缀,然后拼接逻辑视图名称加上前缀和后缀的方式确定视图URL。

UrlBasedViewResolver支持返回视图名称中包括redirect:前缀,以支持在客户端的跳转。比如当访问一个url"/demo",该url对应的handler返回的逻辑视图名为"redirect:/demo1",URLBasedViewResolver在创建视图时(createView方法中),判断逻辑视图名称的前缀是"redirect:"开头,接着裁剪掉"redirect:"前缀后,创建RedirectView对象,RedirectView对象将把请求返回的模型数据组合成查询参数形式拼接到redirect的URL后面,然后调用 HttpServletResponse 对象的 sendRedirect 方法进行重定向。(稍后我们实践验证)

同样的,URLBasedViewResolver还支持"forword:"前缀,然后封装成一个 InternalResourceView 对象,服务器端利用 RequestDispatcher 的 forword 方式跳转到指定的地址。

说了这么多,我们看下源码是如何实现的,如下:

public class UrlBasedViewResolver extends AbstractCachingViewResolver implements Ordered {    ... ...        /** 创建View实例 */    @Override    protected View createView(String viewName, Locale locale) throws Exception {        // If this resolver is not supposed to handle the given view,        // return null to pass on to the next resolver in the chain.        if (!canHandle(viewName, locale)) {            return null;        }        // 处理redirect请求        if (viewName.startsWith(REDIRECT_URL_PREFIX)) {            // 去掉redirect:前缀            String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());            // 根据redirectUrl创建RedirectView实例            RedirectView view = new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible());            String[] hosts = getRedirectHosts();            if (hosts != null) {                view.setHosts(hosts);            }            return applyLifecycleMethods(viewName, view);        }        // 处理forward请求        if (viewName.startsWith(FORWARD_URL_PREFIX)) {            去掉forward:前缀            String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());            return new InternalResourceView(forwardUrl);        }        // Else fall back to superclass implementation: calling loadView.        // 处理普通view(除redirect/forward)        // 调用父类createView方法,然后通过模板方法再调回本例的loadView方法        return super.createView(viewName, locale);    }    @Override    protected View loadView(String viewName, Locale locale) throws Exception {        AbstractUrlBasedView view = buildView(viewName);        View result = applyLifecycleMethods(viewName, view);        return (view.checkResource(locale) ? result : null);    }    ... ...}

InternalResourceViewResolver

InternalResourceViewResolver继承UrlBasedViewResolver,故UrlBaseViewResolver具有的功能,InternalResourceViewResolver同样具备,在实际项目中也是使用最广泛的一种视图解析器。InternalResourceViewResolver会把返回的视图对象解析为InternalResourceView 对象,InternalResourceView 会把 Controller 处理器方法返回的模型属性都存放到对应的 request 属性中,然后通过 RequestDispatcher 在服务器端把请求 forword 重定向到目标 URL。代码如下:

public class InternalResourceViewResolver extends UrlBasedViewResolver {    ... ...    /** 构造函数 */    public InternalResourceViewResolver() {        // 获取InternalResourceView        Class
viewClass = requiredViewClass(); if (InternalResourceView.class == viewClass && jstlPresent) { viewClass = JstlView.class; } setViewClass(viewClass); } @Override protected Class
requiredViewClass() { return InternalResourceView.class; } ... ...}

其他功能都与UrlBasedViewResolver一样。

实战练习

  • UrlBaseViewResolver

Spring配置文件代码如下:

Controller代码如下:

@Controllerpublic class DemoController {    /** 测试redirect */    @GetMapping("/redirect")    public String redirect(ModelMap modelMap){        modelMap.put("name","daliang");        modelMap.put("pass","111");        return "redirect:/demo";    }    /** 测试forward */    @GetMapping("/forward")    public String forward(ModelMap modelMap){        modelMap.put("name","daliang");        modelMap.put("pass","111");        return "forward:/demo";    }    @GetMapping("/demo")    public String demo(){        return "test";    }}

启动应用,在浏览器地址栏输入:8088/redirect,回车后如下:

可见参数拼接到了url后面。

  • InternalResourceViewResolver

此解析器与UrlBasedViewResolver差不多,更改下配置文件中的类全路径即可。

总结

本章介绍了AbstractCachingViewResolver、UrlBasedViewResolver以及InternalResourceViewResolver三个视图解析器。这部分内容有点儿多,我会尽快结束。希望能帮到大家,谢谢!

最后创建了qq群方便大家交流,可扫描加入,同时也可加我qq:276420284,共同学习、共同进步,谢谢!

转载地址:http://mmdia.baihongyu.com/

你可能感兴趣的文章
selenium+testNG+Ant
查看>>
1024程序员节,你屯书了吗?(内含福利)
查看>>
移动端JS 触摸事件基础
查看>>
Flex拖动原来如此简单
查看>>
温故而知新:什么是wcf
查看>>
centos语言设置
查看>>
php安装
查看>>
Fragment在getUserVisibleHint时进行加载数据的问题记录
查看>>
使用线程池模拟处理耗时任务,通过websocket提高用户体验
查看>>
Java 内部类种类及使用解析
查看>>
Axure产品原型设计工具
查看>>
spice在桌面虚拟化中的应用系列之三(USB映射实现,SSL加密,密码认证,多客户端支持)...
查看>>
Loading project 91606170 of 1: Project FooBar 问题如何解决?
查看>>
C# yeild使用
查看>>
MapReduce-Hadoop分布式计算模型
查看>>
StrokePlus
查看>>
joisino's travel
查看>>
组合游戏-博弈论中经典模型题目
查看>>
浅谈HTTP的GET和POST
查看>>
点灯笼
查看>>