22_1 Spring MVC - ViewResolver系列 - AbstractCachingViewResolver
22_1 Spring MVC - ViewResolver系列 - AbstractCachingViewResolver
一、简介
AbstractCachingViewResolver是一个抽象类,这种视图解析器会把它曾经解析过的视图保存起来,然后每次要解析视图的时候先从缓存里面找,如果找对了对应的视图就直接返回,如果没有就创建一个新的视图对象,然后把它放到一个用于缓存的map中,接着再把新建的视图返回。使用这种视图缓存的方式可以把解析视图的性能问题降到最低。
二、源码解析
2.1 缓存视图的 map
// 默认缓存的大小
public static final int DEFAULT_CACHE_LIMIT = 1024;
// 缓存view的map
private final Map<Object, View> viewAccessCache = new ConcurrentHashMap<>(DEFAULT_CACHE_LIMIT);
2.2 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);
}
}
- 先通过 isCache() 判断是否启动缓存
- 如果没有启动缓存,直接通过 createView(viewName, locale) 方法创建视图
- 如果使用了缓存,则先获取key
- key的获取通过 getCacheKey(viewName, locale) 获取
- 在缓存map里获取 view,判断view是不是为null
- 如果为null,采用双重校验饿方式进行安全创建
2.2.1 isCache()
public static final int DEFAULT_CACHE_LIMIT = 1024;
private volatile int cacheLimit = DEFAULT_CACHE_LIMIT;
public boolean isCache() {
return (this.cacheLimit > 0);
}
2.2.2 createView(String viewName, Locale locale)
创建新视图的方法有具体的子类实现。
@Nullable
protected View createView(String viewName, Locale locale) throws Exception {
return loadView(viewName, locale);
}
@Nullable
protected abstract View loadView(String viewName, Locale locale) throws Exception;
2.2.3 getCacheKey(String viewName, Locale locale)
缓存map中的key的规则
protected Object getCacheKey(String viewName, Locale locale) {
return viewName + '_' + locale;
}
知行合一