21
21
import java .util .Collections ;
22
22
import java .util .Map ;
23
23
import java .util .concurrent .ConcurrentHashMap ;
24
- import java .util .concurrent .ConcurrentMap ;
24
+ import java .util .concurrent .CopyOnWriteArrayList ;
25
25
26
26
import com .github .benmanes .caffeine .cache .CacheLoader ;
27
27
import com .github .benmanes .caffeine .cache .Caffeine ;
56
56
*/
57
57
public class CaffeineCacheManager implements CacheManager {
58
58
59
- private final ConcurrentMap <String , Cache > cacheMap = new ConcurrentHashMap <>(16 );
60
-
61
- private boolean dynamic = true ;
62
-
63
59
private Caffeine <Object , Object > cacheBuilder = Caffeine .newBuilder ();
64
60
65
61
@ Nullable
66
62
private CacheLoader <Object , Object > cacheLoader ;
67
63
68
64
private boolean allowNullValues = true ;
69
65
66
+ private boolean dynamic = true ;
67
+
68
+ private final Map <String , Cache > cacheMap = new ConcurrentHashMap <>(16 );
69
+
70
+ private final Collection <String > customCacheNames = new CopyOnWriteArrayList <>();
71
+
70
72
71
73
/**
72
74
* Construct a dynamic CaffeineCacheManager,
@@ -135,6 +137,13 @@ public void setCacheSpecification(String cacheSpecification) {
135
137
doSetCaffeine (Caffeine .from (cacheSpecification ));
136
138
}
137
139
140
+ private void doSetCaffeine (Caffeine <Object , Object > cacheBuilder ) {
141
+ if (!ObjectUtils .nullSafeEquals (this .cacheBuilder , cacheBuilder )) {
142
+ this .cacheBuilder = cacheBuilder ;
143
+ refreshCommonCaches ();
144
+ }
145
+ }
146
+
138
147
/**
139
148
* Set the Caffeine CacheLoader to use for building each individual
140
149
* {@link CaffeineCache} instance, turning it into a LoadingCache.
@@ -145,7 +154,7 @@ public void setCacheSpecification(String cacheSpecification) {
145
154
public void setCacheLoader (CacheLoader <Object , Object > cacheLoader ) {
146
155
if (!ObjectUtils .nullSafeEquals (this .cacheLoader , cacheLoader )) {
147
156
this .cacheLoader = cacheLoader ;
148
- refreshKnownCaches ();
157
+ refreshCommonCaches ();
149
158
}
150
159
}
151
160
@@ -158,7 +167,7 @@ public void setCacheLoader(CacheLoader<Object, Object> cacheLoader) {
158
167
public void setAllowNullValues (boolean allowNullValues ) {
159
168
if (this .allowNullValues != allowNullValues ) {
160
169
this .allowNullValues = allowNullValues ;
161
- refreshKnownCaches ();
170
+ refreshCommonCaches ();
162
171
}
163
172
}
164
173
@@ -183,42 +192,76 @@ public Cache getCache(String name) {
183
192
this .dynamic ? createCaffeineCache (cacheName ) : null );
184
193
}
185
194
195
+
196
+ /**
197
+ * Register the given native Caffeine Cache instance with this cache manager,
198
+ * adapting it to Spring's cache API for exposure through {@link #getCache}.
199
+ * Any number of such custom caches may be registered side by side.
200
+ * <p>This allows for custom settings per cache (as opposed to all caches
201
+ * sharing the common settings in the cache manager's configuration) and
202
+ * is typically used with the Caffeine builder API:
203
+ * {@code registerCustomCache("myCache", Caffeine.newBuilder().maximumSize(10).build())}
204
+ * <p>Note that any other caches, whether statically specified through
205
+ * {@link #setCacheNames} or dynamically built on demand, still operate
206
+ * with the common settings in the cache manager's configuration.
207
+ * @param name the name of the cache
208
+ * @param cache the custom Caffeine Cache instance to register
209
+ * @since 5.2.8
210
+ * @see #adaptCaffeineCache
211
+ */
212
+ public void registerCustomCache (String name , com .github .benmanes .caffeine .cache .Cache <Object , Object > cache ) {
213
+ this .customCacheNames .add (name );
214
+ this .cacheMap .put (name , adaptCaffeineCache (name , cache ));
215
+ }
216
+
186
217
/**
187
- * Create a new CaffeineCache instance for the specified cache name.
218
+ * Adapt the given new native Caffeine Cache instance to Spring's {@link Cache}
219
+ * abstraction for the specified cache name.
188
220
* @param name the name of the cache
221
+ * @param cache the native Caffeine Cache instance
189
222
* @return the Spring CaffeineCache adapter (or a decorator thereof)
223
+ * @since 5.2.8
224
+ * @see CaffeineCache
225
+ * @see #isAllowNullValues()
226
+ */
227
+ protected Cache adaptCaffeineCache (String name , com .github .benmanes .caffeine .cache .Cache <Object , Object > cache ) {
228
+ return new CaffeineCache (name , cache , isAllowNullValues ());
229
+ }
230
+
231
+ /**
232
+ * Build a common {@link CaffeineCache} instance for the specified cache name,
233
+ * using the common Caffeine configuration specified on this cache manager.
234
+ * <p>Delegates to {@link #adaptCaffeineCache} as the adaptation method to
235
+ * Spring's cache abstraction (allowing for centralized decoration etc),
236
+ * passing in a freshly built native Caffeine Cache instance.
237
+ * @param name the name of the cache
238
+ * @return the Spring CaffeineCache adapter (or a decorator thereof)
239
+ * @see #adaptCaffeineCache
240
+ * @see #createNativeCaffeineCache
190
241
*/
191
242
protected Cache createCaffeineCache (String name ) {
192
- return new CaffeineCache (name , createNativeCaffeineCache (name ), isAllowNullValues ( ));
243
+ return adaptCaffeineCache (name , createNativeCaffeineCache (name ));
193
244
}
194
245
195
246
/**
196
- * Create a native Caffeine Cache instance for the specified cache name.
247
+ * Build a common Caffeine Cache instance for the specified cache name,
248
+ * using the common Caffeine configuration specified on this cache manager.
197
249
* @param name the name of the cache
198
250
* @return the native Caffeine Cache instance
251
+ * @see #createCaffeineCache
199
252
*/
200
253
protected com .github .benmanes .caffeine .cache .Cache <Object , Object > createNativeCaffeineCache (String name ) {
201
- if (this .cacheLoader != null ) {
202
- return this .cacheBuilder .build (this .cacheLoader );
203
- }
204
- else {
205
- return this .cacheBuilder .build ();
206
- }
207
- }
208
-
209
- private void doSetCaffeine (Caffeine <Object , Object > cacheBuilder ) {
210
- if (!ObjectUtils .nullSafeEquals (this .cacheBuilder , cacheBuilder )) {
211
- this .cacheBuilder = cacheBuilder ;
212
- refreshKnownCaches ();
213
- }
254
+ return (this .cacheLoader != null ? this .cacheBuilder .build (this .cacheLoader ) : this .cacheBuilder .build ());
214
255
}
215
256
216
257
/**
217
- * Create the known caches again with the current state of this manager.
258
+ * Recreate the common caches with the current state of this manager.
218
259
*/
219
- private void refreshKnownCaches () {
260
+ private void refreshCommonCaches () {
220
261
for (Map .Entry <String , Cache > entry : this .cacheMap .entrySet ()) {
221
- entry .setValue (createCaffeineCache (entry .getKey ()));
262
+ if (!this .customCacheNames .contains (entry .getKey ())) {
263
+ entry .setValue (createCaffeineCache (entry .getKey ()));
264
+ }
222
265
}
223
266
}
224
267
0 commit comments