IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring MVC组件之ViewResolver -> 正文阅读

[Java知识库]Spring MVC组件之ViewResolver

Spring MVC组件之ViewResolver

ViewResolver概述

ViewResolver组件的作用主要根据视图名和本地化的Locale,来解析出相应的视图View对象。

在SpringMvc的源码中,ViewResolver是一个接口。该接口主要定义了一个方法。

  • View resolveViewName(String viewName, Locale locale)

接口方法中需要viewName 和locale两个参数,viewName是视图名称,locale是本地化的参数。一般情况下,我们只需要通过viewName来找到相应的视图。在国际化的场景中,可以根据不同的locale来展示不同语言的视图。

ViewResolver类图

?

从以上类图中可以看出,AbstractCachingViewResolverBeanNameViewResolverContentNegotiatingViewResolverViewResolverComposite这四个类直接继承至 ViewResolver接口,都只有一层继承结构。

只有AbstractCachingViewResolver类的继承关系相对来说复杂一些,AbstractCachingViewResolver类可以缓存已经解析过的视图。

AbstractCachingViewResolver系列

AbstractCachingViewResolver

AbstractCachingViewResolver类是一个抽象类。它提供了对View的缓存功能,当视图解析过一次就被缓存起来, 直到缓存的视图被删除前,视图解析都是自动从缓存中获取的。

AbstractCachingViewResolver类继承了WebApplicationObjectSupport父类,实现了ViewResolver接口。

AbstractCachingViewResolver类实现了ViewResolver接口的resolveViewName方法。

??? @Override

??? @Nullable

??? public View resolveViewName(String viewName, Locale locale) throws Exception {

??????? 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) {

?????????????????????? // Ask the subclass to create the View object.

?????????????????????? 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 + "]");

?????????????????????????? }

?????????????????????? }

?????????????????? }

?????????????? }

?????????? }

?????????? return (view != UNRESOLVED_VIEW ? view : null);

??????? }

}

resolveViewName方法中主要做了以下几件事情。

  1. 首先要判断是否开启缓存。如果没有开启缓存,就直接调用createView(viewName, locale)方法,来创建一个视图。
  2. 如果有开启缓存,首先获取视图缓存的key值。然后再通过key值,在viewAccessCache缓存中获取视图。如果视图存在就直接返回。
  3. 如果viewAccessCache缓存中不存在该视图,则到viewCreationCache缓存中去找这个视图,找到就返回该视图。
  4. 如果viewCreationCache缓存中也不存在该视图,则再调用createView(viewName, locale)方法来创建一个视图返回。并把创建的视图放到viewAccessCacheviewCreationCache的缓存中。

createView方法中,其实又调用了loadView方法。loadView方法在AbstractCachingViewResolver类中只是一个抽象方法,专门留给子类来实现自身的业务逻辑。

AbstractCachingViewResolver类的缓存

AbstractCachingViewResolver类中,使用了viewAccessCacheviewCreationCache两个HashMap来做缓存。

viewAccessCacheConcurrentHashMap的类型。ConcurrentHashMap是一个支持高并发,线程安全,高效的哈希表。

viewCreationCacheLinkedHashMap类型的。LinkedHashMapHashMap和双向链表的组合,它通过维护一个双向链表保证了值是有序的。LinkedHashMap中有一个removeEldestEntry方法。该方法返回一个boolearn值,当返回值为true的时候,LinkedHashMap会自动删除最前面的一个Map值。该方法是在putputAll方法被调用是被触发。

AbstractCachingViewResolver类中,是这样定义viewCreationCache的。viewCreationCache的重写了父类的removeEldestEntry方法。在该方法中会判断视图的数量是否超过了限制。如果已超过限制,就会先在viewAccessCache缓存删除掉最先缓存的视图。然后返回true, viewCreationCache就会制动删除这个视图。这样就将两种类型的map各自优势结合起来了。

@SuppressWarnings("serial")

??? private final Map<Object, View> viewCreationCache =

????????? new LinkedHashMap<Object, View>(DEFAULT_CACHE_LIMIT, 0.75f, true) {

?????????????? @Override

?????????????? protected boolean removeEldestEntry(Map.Entry<Object, View> eldest) {

?????????????????? if (size() > getCacheLimit()) {

?????????????????????? viewAccessCache.remove(eldest.getKey());

?????????????????????? return true;

?????????????????? }

?????????????????? else {

?????????????????????? return false;

?????????????????? }

?????????????? }

????????? };

UrlBasedViewResolver

UrlBasedViewResolver直接继承了AbstractCachingViewResolver类。它是对viewResolvers接口一个比较基本的实现。它提供了一种URL拼接的方式来解析视图。

UrlBasedViewResolver类可以通过prefix属性和suffix属性,来分别设置一个前缀和后缀,最后视图的URL就是前缀+逻辑视图+后缀。

它主要重写了父类的getCacheKeycreateViewloadView三个方法。

  • getCacheKey方法
@Override

protected Object getCacheKey(String viewName, Locale locale) {

return viewName;

}

getCacheKey方法直接返回viewName,舍弃了locale这个参数。可见UrlBasedViewResolver类是不支持Locale

  • createView

?

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;

????? }



????? // Check for special "redirect:" prefix.

????? if (viewName.startsWith(REDIRECT_URL_PREFIX)) {

????????? String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());

????????? RedirectView view = new RedirectView(redirectUrl,

???????????????? isRedirectContextRelative(), isRedirectHttp10Compatible());

????????? String[] hosts = getRedirectHosts();

????????? if (hosts != null) {

????????????? view.setHosts(hosts);

????????? }

????????? return applyLifecycleMethods(REDIRECT_URL_PREFIX, view);

????? }



????? // Check for special "forward:" prefix.

????? if (viewName.startsWith(FORWARD_URL_PREFIX)) {

????????? String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());

????????? return new InternalResourceView(forwardUrl);

????? }



????? // Else fall back to superclass implementation: calling loadView.

????? return super.createView(viewName, locale);

? }

createView方法主要做了以下四件事情。

  1. canHandle方法中,通过视图名称来检查视图是否能被解析。
  2. 判断视图名称是否是以“redirect:”开头,如果是,则创建一个RedirectView类型的视图返回。RedirectView视图是用于重定向跳转。
  3. 再判断视图名称是否是以“forward:”开头,如果是,则创建一个InternalResourceView类型的forward视图返回。forward视图是用于转发操作。
  4. 如果不是以上的3种情况,则调用父类的createView方法。父类的createView方法又会调用loadView方法。

  • loadView方法
??? @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);

? }

loadView方法主要做了三件事情。

  1. 使用buildView方法创建一个视图。在buildView方法中根据视图的类型,使用了org.springframework.beans.BeanUtils.instantiateClass方法,创建了一个AbstractUrlBasedView类型的实例。AbstractUrlBasedView的实例创建好后,再对这个实例进行一些属性的设置。

视图中的url属性就是在这里设置的,url就是前缀加视图名再加后缀组合而成的。

  1. 使用applyLifecycleMethods方法,对创建的视图进行初始化的设置。
  2. 判断视图模板是否存在,如存在则返回,不存在就返回NULL值。

UrlBasedViewResolver实现了视图解析的基本功能,作为UrlBasedViewResolver类的子类只需要重写父类的两个方法,便可实现自己的功能。

  • 重写了父类的requiredViewClass方法,在这个方法中返回自己的类型。
  • 类重写了父类的buildView方法,先调用父类的buildView方法得到一个View对象后,再对该对设置自己独有的属性。

InternalResourceViewResolver

InternalResourceViewResolver类继承至UrlBasedViewResolver类。Spring MVC容器在初始化ViewResolver类型的组件时,初始化的就有InternalResourceViewResolver组件。在实际应用中InternalResourceViewResolver也是使用的最广泛的一个视图解析器。InternalResourceViewResolver会把返回的视图名称都解析为InternalResourceView对象。

InternalResourceViewResolver类重写了父类的requiredViewClass方法,返回的是InternalResourceView类型。

InternalResourceViewResolver类重写了父类的buildView方法,在buildView方法中,先调用父类的方法构建一个InternalResourceView对象。再设置对象InternalResourceView的alwaysInclude,preventDispatchLoop的属性值。

ViewResolverComposite

ViewResolverComposite类继承至ViewResolver接口。从ViewResolverComposite类名称可以知道它是一系列ViewResolver的组合。

ViewResolverComposite类中有一个属性是viewResolvers。它是一个ViewResolver类型的集合。我们可以对这个属性值进行设置。

ViewResolverComposite类实现了ViewResolver接口的resolveViewName方法。在resolveViewName方法中,程序会循环遍历viewResolvers集合,针对集合中的每一个ViewResolver的实例。调用每一个实例的resolveViewName方法,直到得到一个View为止。代码如下所示:

??? @Override

??? @Nullable

??? public View resolveViewName(String viewName, Locale locale) throws Exception {

??????? for (ViewResolver viewResolver : this.viewResolvers) {

?????????? View view = viewResolver.resolveViewName(viewName, locale);

?????????? if (view != null) {

?????????????? return view;

?????????? }

??????? }

??????? return null;

}

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-09-13 10:59:34  更:2022-09-13 10:59:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 12:26:38-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码