17
17
18
18
import java .nio .charset .StandardCharsets ;
19
19
import java .time .Duration ;
20
- import java .util .function .BiFunction ;
21
20
import java .util .function .Consumer ;
22
21
23
22
import org .springframework .cache .Cache ;
35
34
* Immutable {@link RedisCacheConfiguration} used to customize {@link RedisCache} behaviour, such as caching
36
35
* {@literal null} values, computing cache key prefixes and handling binary serialization.
37
36
* <p>
38
- * Start with {@link RedisCacheConfiguration#defaultCacheConfig()} and customize {@link RedisCache} behaviour
39
- * from that point on.
37
+ * Start with {@link RedisCacheConfiguration#defaultCacheConfig()} and customize {@link RedisCache} behaviour from that
38
+ * point on.
40
39
*
41
40
* @author Christoph Strobl
42
41
* @author Mark Paluch
@@ -109,8 +108,7 @@ public static RedisCacheConfiguration defaultCacheConfig(@Nullable ClassLoader c
109
108
registerDefaultConverters (conversionService );
110
109
111
110
return new RedisCacheConfiguration ((k , v ) -> Duration .ZERO , DEFAULT_CACHE_NULL_VALUES , DEFAULT_USE_PREFIX ,
112
- CacheKeyPrefix .simple (),
113
- SerializationPair .fromSerializer (RedisSerializer .string ()),
111
+ CacheKeyPrefix .simple (), SerializationPair .fromSerializer (RedisSerializer .string ()),
114
112
SerializationPair .fromSerializer (RedisSerializer .java (classLoader )), conversionService );
115
113
}
116
114
@@ -121,17 +119,17 @@ public static RedisCacheConfiguration defaultCacheConfig(@Nullable ClassLoader c
121
119
122
120
private final ConversionService conversionService ;
123
121
124
- private final BiFunction < Object , Object , Duration > ttlProvider ;
122
+ private final TtlFunction ttlFunction ;
125
123
126
124
private final SerializationPair <String > keySerializationPair ;
127
125
private final SerializationPair <Object > valueSerializationPair ;
128
126
129
127
@ SuppressWarnings ("unchecked" )
130
- private RedisCacheConfiguration (BiFunction < Object , Object , Duration > ttlProvider , Boolean cacheNullValues , Boolean usePrefix , CacheKeyPrefix keyPrefix ,
131
- SerializationPair < String > keySerializationPair , SerializationPair <?> valueSerializationPair ,
132
- ConversionService conversionService ) {
128
+ private RedisCacheConfiguration (TtlFunction ttlFunction , Boolean cacheNullValues , Boolean usePrefix ,
129
+ CacheKeyPrefix keyPrefix , SerializationPair <String > keySerializationPair ,
130
+ SerializationPair <?> valueSerializationPair , ConversionService conversionService ) {
133
131
134
- this .ttlProvider = ttlProvider ;
132
+ this .ttlFunction = ttlFunction ;
135
133
this .cacheNullValues = cacheNullValues ;
136
134
this .usePrefix = usePrefix ;
137
135
this .keyPrefix = keyPrefix ;
@@ -167,7 +165,7 @@ public RedisCacheConfiguration computePrefixWith(CacheKeyPrefix cacheKeyPrefix)
167
165
168
166
Assert .notNull (cacheKeyPrefix , "Function for computing prefix must not be null" );
169
167
170
- return new RedisCacheConfiguration (ttlProvider , cacheNullValues , DEFAULT_USE_PREFIX , cacheKeyPrefix ,
168
+ return new RedisCacheConfiguration (ttlFunction , cacheNullValues , DEFAULT_USE_PREFIX , cacheKeyPrefix ,
171
169
keySerializationPair , valueSerializationPair , conversionService );
172
170
}
173
171
@@ -180,8 +178,8 @@ public RedisCacheConfiguration computePrefixWith(CacheKeyPrefix cacheKeyPrefix)
180
178
* @return new {@link RedisCacheConfiguration}.
181
179
*/
182
180
public RedisCacheConfiguration disableCachingNullValues () {
183
- return new RedisCacheConfiguration (ttlProvider , DO_NOT_CACHE_NULL_VALUES , usePrefix , keyPrefix , keySerializationPair ,
184
- valueSerializationPair , conversionService );
181
+ return new RedisCacheConfiguration (ttlFunction , DO_NOT_CACHE_NULL_VALUES , usePrefix , keyPrefix ,
182
+ keySerializationPair , valueSerializationPair , conversionService );
185
183
}
186
184
187
185
/**
@@ -193,7 +191,7 @@ public RedisCacheConfiguration disableCachingNullValues() {
193
191
*/
194
192
public RedisCacheConfiguration disableKeyPrefix () {
195
193
196
- return new RedisCacheConfiguration (ttlProvider , cacheNullValues , DO_NOT_USE_PREFIX , keyPrefix , keySerializationPair ,
194
+ return new RedisCacheConfiguration (ttlFunction , cacheNullValues , DO_NOT_USE_PREFIX , keyPrefix , keySerializationPair ,
197
195
valueSerializationPair , conversionService );
198
196
}
199
197
@@ -207,22 +205,22 @@ public RedisCacheConfiguration entryTtl(Duration ttl) {
207
205
208
206
Assert .notNull (ttl , "TTL duration must not be null" );
209
207
210
- return new RedisCacheConfiguration ((k , v ) -> ttl , cacheNullValues , usePrefix , keyPrefix , keySerializationPair ,
211
- valueSerializationPair , conversionService );
208
+ return entryTtl (new SingletonTtlFunction (ttl ));
212
209
}
213
210
214
211
/**
215
- * Set the ttl Provider, which can dynamic provide ttl to apply for cache entries.
216
- * @param ttlProvider {@link BiFunction} calculate ttl with the actual original cache key and value,
217
- * which must not be {@literal null}, and the ttl must not be {@literal null} either.
212
+ * Set the {@link TtlFunction TTL function} to compute the time to live for cache entries.
218
213
*
214
+ * @param ttlFunction the {@link TtlFunction} to compute the time to live for cache entries, must not be
215
+ * {@literal null}.
219
216
* @return new {@link RedisCacheConfiguration}.
217
+ * @since 3.2
220
218
*/
221
- public RedisCacheConfiguration entryTtlProvider ( BiFunction < Object , Object , Duration > ttlProvider ) {
219
+ public RedisCacheConfiguration entryTtl ( TtlFunction ttlFunction ) {
222
220
223
- Assert .notNull (ttlProvider , "ttlProvider must not be null" );
221
+ Assert .notNull (ttlFunction , "TtlFunction must not be null" );
224
222
225
- return new RedisCacheConfiguration (ttlProvider , cacheNullValues , usePrefix , keyPrefix , keySerializationPair ,
223
+ return new RedisCacheConfiguration (ttlFunction , cacheNullValues , usePrefix , keyPrefix , keySerializationPair ,
226
224
valueSerializationPair , conversionService );
227
225
}
228
226
@@ -236,7 +234,7 @@ public RedisCacheConfiguration serializeKeysWith(SerializationPair<String> keySe
236
234
237
235
Assert .notNull (keySerializationPair , "KeySerializationPair must not be null" );
238
236
239
- return new RedisCacheConfiguration (ttlProvider , cacheNullValues , usePrefix , keyPrefix , keySerializationPair ,
237
+ return new RedisCacheConfiguration (ttlFunction , cacheNullValues , usePrefix , keyPrefix , keySerializationPair ,
240
238
valueSerializationPair , conversionService );
241
239
}
242
240
@@ -250,7 +248,7 @@ public RedisCacheConfiguration serializeValuesWith(SerializationPair<?> valueSer
250
248
251
249
Assert .notNull (valueSerializationPair , "ValueSerializationPair must not be null" );
252
250
253
- return new RedisCacheConfiguration (ttlProvider , cacheNullValues , usePrefix , keyPrefix , keySerializationPair ,
251
+ return new RedisCacheConfiguration (ttlFunction , cacheNullValues , usePrefix , keyPrefix , keySerializationPair ,
254
252
valueSerializationPair , conversionService );
255
253
}
256
254
@@ -264,8 +262,8 @@ public RedisCacheConfiguration withConversionService(ConversionService conversio
264
262
265
263
Assert .notNull (conversionService , "ConversionService must not be null" );
266
264
267
- return new RedisCacheConfiguration (ttlProvider , cacheNullValues , usePrefix , keyPrefix , keySerializationPair ,
268
- valueSerializationPair , conversionService );
265
+ return new RedisCacheConfiguration (ttlFunction , cacheNullValues , usePrefix , keyPrefix , keySerializationPair ,
266
+ valueSerializationPair , conversionService );
269
267
}
270
268
271
269
/**
@@ -319,26 +317,26 @@ public SerializationPair<Object> getValueSerializationPair() {
319
317
320
318
/**
321
319
* @return The constant expiration time (ttl) for cache entries. Never {@literal null}.
320
+ * @deprecated since 3.2, use {@link #getTtlFunction()} instead.
322
321
*/
322
+ @ Deprecated (since = "3.2" , forRemoval = true )
323
323
public Duration getTtl () {
324
- Duration ttl = ttlProvider .apply (Object .class , Object .class );
325
- Assert .notNull (ttl , "TTL duration must not be null" );
326
- return ttl ;
324
+ return getTtlFunction ().getTimeToLive (Object .class , null );
327
325
}
328
326
329
327
/**
330
- * @return The expiration time (ttl) for cache entries with original key and value. Never {@literal null}.
328
+ * Returns the function to compute the time to live.
329
+ *
330
+ * @return the function to compute the time to live.
331
+ * @since 3.2
331
332
*/
332
- public Duration getTtl (Object key , Object val ) {
333
- Duration ttl = ttlProvider .apply (key , val );
334
- Assert .notNull (ttl , "TTL duration must not be null" );
335
-
336
- return ttl ;
333
+ public TtlFunction getTtlFunction () {
334
+ return ttlFunction ;
337
335
}
338
336
339
337
/**
340
- * Adds a {@link Converter} to extract the {@link String} representation of a {@literal cache key}
341
- * if no suitable {@link Object#toString()} method is present.
338
+ * Adds a {@link Converter} to extract the {@link String} representation of a {@literal cache key} if no suitable
339
+ * {@link Object#toString()} method is present.
342
340
*
343
341
* @param cacheKeyConverter {@link Converter} used to convert a {@literal cache key} into a {@link String}.
344
342
* @throws IllegalStateException if {@link #getConversionService()} does not allow {@link Converter} registration.
@@ -352,8 +350,8 @@ public void addCacheKeyConverter(Converter<?, String> cacheKeyConverter) {
352
350
/**
353
351
* Configure the underlying {@link ConversionService} used to extract the {@literal cache key}.
354
352
*
355
- * @param registryConsumer {@link Consumer} used to register a {@link Converter}
356
- * with the configured {@link ConverterRegistry}; never {@literal null}.
353
+ * @param registryConsumer {@link Consumer} used to register a {@link Converter} with the configured
354
+ * {@link ConverterRegistry}; never {@literal null}.
357
355
* @throws IllegalStateException if {@link #getConversionService()} does not allow {@link Converter} registration.
358
356
* @see org.springframework.core.convert.converter.ConverterRegistry
359
357
* @since 2.2
@@ -381,8 +379,8 @@ public void configureKeyConverters(Consumer<ConverterRegistry> registryConsumer)
381
379
* <li>{@link SimpleKey} to {@link String}</li>
382
380
* </ul>
383
381
*
384
- * @param registry {@link ConverterRegistry} in which the {@link Converter key converters} are registered;
385
- * must not be {@literal null}.
382
+ * @param registry {@link ConverterRegistry} in which the {@link Converter key converters} are registered; must not be
383
+ * {@literal null}.
386
384
* @see org.springframework.core.convert.converter.ConverterRegistry
387
385
*/
388
386
public static void registerDefaultConverters (ConverterRegistry registry ) {
@@ -392,4 +390,34 @@ public static void registerDefaultConverters(ConverterRegistry registry) {
392
390
registry .addConverter (String .class , byte [].class , source -> source .getBytes (StandardCharsets .UTF_8 ));
393
391
registry .addConverter (SimpleKey .class , String .class , SimpleKey ::toString );
394
392
}
393
+
394
+ /**
395
+ * Function to compute the time to live from the cache {@code key} and {@code value}.
396
+ *
397
+ * @author Mark Paluch
398
+ * @since 3.2
399
+ */
400
+ @ FunctionalInterface
401
+ interface TtlFunction {
402
+
403
+ /**
404
+ * Compute a {@link Duration time to live duration} using the cache {@code key} and {@code value}. The time to live
405
+ * is computed on each write operation. Redis uses milliseconds granularity for timeouts. Any more granular values
406
+ * (e.g. micros or nanos) are not considered and are truncated due to rounding. Returning {@link Duration#ZERO} (or
407
+ * a value less than {@code Duration.ofMillis(1)}) results in a persistent value that does not expire.
408
+ *
409
+ * @param key the cache key.
410
+ * @param value the cache value. Can be {@code null} if the cache supports {@code null} value caching.
411
+ * @return the time to live. Can be {@link Duration#ZERO} for persistent values (i.e. cache entry does not expire).
412
+ */
413
+ Duration getTimeToLive (Object key , @ Nullable Object value );
414
+ }
415
+
416
+ private record SingletonTtlFunction (Duration duration ) implements TtlFunction {
417
+
418
+ @ Override
419
+ public Duration getTimeToLive (Object key , @ Nullable Object value ) {
420
+ return this .duration ;
421
+ }
422
+ }
395
423
}
0 commit comments