Skip to content

Commit 8b1a2a7

Browse files
committed
Merge pull request #22606 from fred84/22391_conditional_view_caching
* 22391_conditional_view_caching: Polish contribution Add filter to AbstractCachingViewResolver
2 parents 4612544 + 132fa70 commit 8b1a2a7

File tree

2 files changed

+87
-2
lines changed

2 files changed

+87
-2
lines changed

spring-webmvc/src/main/java/org/springframework/web/servlet/view/AbstractCachingViewResolver.java

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
2424
import javax.servlet.http.HttpServletResponse;
2525

2626
import org.springframework.lang.Nullable;
27+
import org.springframework.util.Assert;
2728
import org.springframework.web.context.support.WebApplicationObjectSupport;
2829
import org.springframework.web.servlet.View;
2930
import org.springframework.web.servlet.ViewResolver;
@@ -58,13 +59,19 @@ public void render(@Nullable Map<String, ?> model, HttpServletRequest request, H
5859
}
5960
};
6061

62+
/** Default cache filter that always caches. */
63+
private static final CacheFilter DEFAULT_CACHE_FILTER = (view, viewName, locale) -> true;
64+
6165

6266
/** The maximum number of entries in the cache. */
6367
private volatile int cacheLimit = DEFAULT_CACHE_LIMIT;
6468

6569
/** Whether we should refrain from resolving views again if unresolved once. */
6670
private boolean cacheUnresolved = true;
6771

72+
/** Filter function that determines if view should be cached. */
73+
private CacheFilter cacheFilter = DEFAULT_CACHE_FILTER;
74+
6875
/** Fast access cache for Views, returning already cached instances without a global lock. */
6976
private final Map<Object, View> viewAccessCache = new ConcurrentHashMap<>(DEFAULT_CACHE_LIMIT);
7077

@@ -141,6 +148,21 @@ public boolean isCacheUnresolved() {
141148
return this.cacheUnresolved;
142149
}
143150

151+
/**
152+
* Sets the filter that determines if view should be cached.
153+
* Default behaviour is to cache all views.
154+
*/
155+
public void setCacheFilter(CacheFilter cacheFilter) {
156+
Assert.notNull(cacheFilter, "CacheFilter must not be null");
157+
this.cacheFilter = cacheFilter;
158+
}
159+
160+
/**
161+
* Return filter function that determines if view should be cached.
162+
*/
163+
public CacheFilter getCacheFilter() {
164+
return this.cacheFilter;
165+
}
144166

145167
@Override
146168
@Nullable
@@ -160,7 +182,7 @@ public View resolveViewName(String viewName, Locale locale) throws Exception {
160182
if (view == null && this.cacheUnresolved) {
161183
view = UNRESOLVED_VIEW;
162184
}
163-
if (view != null) {
185+
if (view != null && this.cacheFilter.filter(view, viewName, locale)) {
164186
this.viewAccessCache.put(cacheKey, view);
165187
this.viewCreationCache.put(cacheKey, view);
166188
}
@@ -266,4 +288,26 @@ protected View createView(String viewName, Locale locale) throws Exception {
266288
@Nullable
267289
protected abstract View loadView(String viewName, Locale locale) throws Exception;
268290

291+
292+
/**
293+
* Filter that determines if view should be cached.
294+
*
295+
* @author Sergey Galkin
296+
* @author Arjen Poutsma
297+
* @since 5.2
298+
*/
299+
@FunctionalInterface
300+
public interface CacheFilter {
301+
302+
/**
303+
* Indicates whether the given view should be cached. The name and
304+
* locale used to resolve the view are also provided.
305+
* @param view the view
306+
* @param viewName the name used to resolve {@code view}
307+
* @param locale the locale used to resolve {@code view}
308+
* @return {@code true} if the view should be cached; {@code false}
309+
* otherwise
310+
*/
311+
boolean filter(View view, String viewName, Locale locale);
312+
}
269313
}

spring-webmvc/src/test/java/org/springframework/web/servlet/view/ViewResolverTests.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,47 @@ protected View loadView(String viewName, Locale locale) {
516516
assertThat(count.intValue()).isEqualTo(3);
517517
}
518518

519+
@Test
520+
public void cacheFilterEnabled() throws Exception {
521+
AtomicInteger count = new AtomicInteger();
522+
523+
// filter is enabled by default
524+
AbstractCachingViewResolver viewResolver = new AbstractCachingViewResolver() {
525+
@Override
526+
protected View loadView(String viewName, Locale locale) {
527+
assertThat(viewName).isEqualTo("view");
528+
assertThat(locale).isEqualTo(Locale.getDefault());
529+
count.incrementAndGet();
530+
return new TestView();
531+
}
532+
};
533+
534+
viewResolver.resolveViewName("view", Locale.getDefault());
535+
viewResolver.resolveViewName("view", Locale.getDefault());
536+
537+
assertThat(count.intValue()).isEqualTo(1);
538+
}
539+
540+
@Test
541+
public void cacheFilterDisabled() throws Exception {
542+
AtomicInteger count = new AtomicInteger();
543+
544+
AbstractCachingViewResolver viewResolver = new AbstractCachingViewResolver() {
545+
@Override
546+
protected View loadView(String viewName, Locale locale) {
547+
count.incrementAndGet();
548+
return new TestView();
549+
}
550+
};
551+
552+
viewResolver.setCacheFilter((view, viewName, locale) -> false);
553+
554+
viewResolver.resolveViewName("view", Locale.getDefault());
555+
viewResolver.resolveViewName("view", Locale.getDefault());
556+
557+
assertThat(count.intValue()).isEqualTo(2);
558+
}
559+
519560

520561
public static class TestView extends InternalResourceView {
521562

0 commit comments

Comments
 (0)