+ * Enabling this option applies the same {@link #getTtlFunction() TTL expiration policy} to {@link Cache} read + * operations as it does for {@link Cache} write operations. In effect, this will invoke the Redis {@literal GETEX} + * command in place of {@literal GET}. + *
+ * Redis does not support the concept of {@literal TTI}, only {@literal TTL}. However, if {@literal TTL} expiration
+ * is applied to all {@link Cache} operations, both read and write alike, and {@link Cache} operations passed with
+ * expiration are used consistently across the application, then in effect, an application can achieve
+ * {@literal TTI} expiration-like behavior.
+ *
+ * @return this {@link RedisCacheConfiguration}.
+ * @see GETEX
+ * @since 3.2.0
+ */
+ public RedisCacheConfiguration enableTimeToIdle() {
+ return new RedisCacheConfiguration(getTtlFunction(), getAllowCacheNullValues(), USE_TIME_TO_IDLE_EXPIRATION,
+ usePrefix(), getKeyPrefix(), getKeySerializationPair(), getValueSerializationPair(),
+ getConversionService());
}
/**
@@ -222,8 +254,9 @@ public RedisCacheConfiguration entryTtl(TtlFunction ttlFunction) {
Assert.notNull(ttlFunction, "TtlFunction must not be null");
- return new RedisCacheConfiguration(ttlFunction, getAllowCacheNullValues(), usePrefix(), getKeyPrefix(),
- getKeySerializationPair(), getValueSerializationPair(), getConversionService());
+ return new RedisCacheConfiguration(ttlFunction, getAllowCacheNullValues(), isTimeToIdleEnabled(),
+ usePrefix(), getKeyPrefix(), getKeySerializationPair(), getValueSerializationPair(),
+ getConversionService());
}
/**
@@ -236,8 +269,8 @@ public RedisCacheConfiguration serializeKeysWith(SerializationPair
+ * Use {@link #enableTimeToIdle()} to opt-in and enable {@literal time-to-idle (TTI) expiration} for caching.
+ *
+ * @return {@literal true} if {@literal time-to-idle (TTI) expiration} was configured and enabled for caching.
+ * Defaults to {@literal false}.
+ * @see GETEX
+ * @since 3.2.0
+ */
+ public boolean isTimeToIdleEnabled() {
+ return this.enableTimeToIdle;
+ }
+
/**
* @return {@literal true} if cache keys need to be prefixed with the {@link #getKeyPrefixFor(String)} if present or
* the default which resolves to {@link Cache#getName()}.
diff --git a/src/main/java/org/springframework/data/redis/cache/RedisCacheManager.java b/src/main/java/org/springframework/data/redis/cache/RedisCacheManager.java
index 101ef98e3b..9f0d42fa33 100644
--- a/src/main/java/org/springframework/data/redis/cache/RedisCacheManager.java
+++ b/src/main/java/org/springframework/data/redis/cache/RedisCacheManager.java
@@ -22,7 +22,6 @@
import java.util.Map;
import java.util.Optional;
import java.util.Set;
-import java.util.stream.Collectors;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
@@ -67,10 +66,10 @@ public static RedisCacheManagerBuilder builder() {
/**
* Factory method returning a {@literal Builder} used to construct and configure a {@link RedisCacheManager}
- * using the given {@link RedisCacheWriter}.
+ * initialized with the given {@link RedisCacheWriter}.
*
- * @param cacheWriter {@link RedisCacheWriter} used to perform {@link RedisCache} operations by executing
- * appropriate Redis commands; must not be {@literal null}.
+ * @param cacheWriter {@link RedisCacheWriter} used to perform {@link RedisCache} operations
+ * by executing appropriate Redis commands; must not be {@literal null}.
* @return new {@link RedisCacheManagerBuilder}.
* @throws IllegalArgumentException if the given {@link RedisCacheWriter} is {@literal null}.
* @see org.springframework.data.redis.cache.RedisCacheWriter
@@ -84,7 +83,7 @@ public static RedisCacheManagerBuilder builder(RedisCacheWriter cacheWriter) {
/**
* Factory method returning a {@literal Builder} used to construct and configure a {@link RedisCacheManager}
- * using the given {@link RedisConnectionFactory}.
+ * initialized with the given {@link RedisConnectionFactory}.
*
* @param connectionFactory {@link RedisConnectionFactory} used by the {@link RedisCacheManager}
* to acquire connections to Redis when performing {@link RedisCache} operations; must not be {@literal null}.
@@ -100,8 +99,8 @@ public static RedisCacheManagerBuilder builder(RedisConnectionFactory connection
}
/**
- * Factory method used to construct a new {@link RedisCacheManager} using the given {@link RedisConnectionFactory}
- * with caching defaults applied.
+ * Factory method used to construct a new {@link RedisCacheManager} initialized with
+ * the given {@link RedisConnectionFactory} and using the defaults for caching.
*
*
+ * Allows {@link RedisCache cache} creation at runtime.
*
* @param cacheWriter {@link RedisCacheWriter} used to perform {@link RedisCache} operations
* by executing appropriate Redis commands; must not be {@literal null}.
@@ -161,13 +160,13 @@ public RedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration d
/**
* Creates a new {@link RedisCacheManager} initialized with the given {@link RedisCacheWriter}
- * and a default {@link RedisCacheConfiguration}, and whether to allow cache creation at runtime.
+ * and default {@link RedisCacheConfiguration}, and whether to allow cache creation at runtime.
*
* @param cacheWriter {@link RedisCacheWriter} used to perform {@link RedisCache} operations
* by executing appropriate Redis commands; must not be {@literal null}.
* @param defaultCacheConfiguration {@link RedisCacheConfiguration} applied to new {@link RedisCache Redis caches}
* by default when no cache-specific {@link RedisCacheConfiguration} is provided; must not be {@literal null}.
- * @param allowRuntimeCacheCreation boolean to allow creation of undeclared caches at runtime;
+ * @param allowRuntimeCacheCreation boolean specifying whether to allow creation of undeclared caches at runtime;
* {@literal true} by default. Maybe just use {@link RedisCacheConfiguration#defaultCacheConfig()}.
* @throws IllegalArgumentException if either the given {@link RedisCacheWriter} or {@link RedisCacheConfiguration}
* are {@literal null}.
@@ -190,8 +189,8 @@ private RedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration
* Creates a new {@link RedisCacheManager} initialized with the given {@link RedisCacheWriter}
* and a default {@link RedisCacheConfiguration}, along with an optional, initial set of {@link String cache names}
* used to create {@link RedisCache Redis caches} on startup.
- *
- * Allows cache creation at runtime.
+ *
+ * Allows {@link RedisCache cache} creation at runtime.
*
* @param cacheWriter {@link RedisCacheWriter} used to perform {@link RedisCache} operations
* by executing appropriate Redis commands; must not be {@literal null}.
@@ -213,15 +212,15 @@ public RedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration d
/**
* Creates a new {@link RedisCacheManager} initialized with the given {@link RedisCacheWriter}
* and default {@link RedisCacheConfiguration}, and whether to allow cache creation at runtime.
- *
- * Additionally, the optional, initial set of {@link String cache names} witll be used to create
+ *
+ * Additionally, the optional, initial set of {@link String cache names} will be used to create
* {@link RedisCache Redis caches} on startup.
*
* @param cacheWriter {@link RedisCacheWriter} used to perform {@link RedisCache} operations
* by executing appropriate Redis commands; must not be {@literal null}.
* @param defaultCacheConfiguration {@link RedisCacheConfiguration} applied to new {@link RedisCache Redis caches}
* by default when no cache-specific {@link RedisCacheConfiguration} is provided; must not be {@literal null}.
- * @param allowRuntimeCacheCreation boolean to allow creation of undeclared caches at runtime;
+ * @param allowRuntimeCacheCreation boolean specifying whether to allow creation of undeclared caches at runtime;
* {@literal true} by default. Maybe just use {@link RedisCacheConfiguration#defaultCacheConfig()}.
* @param initialCacheNames optional set of {@link String cache names} used to create {@link RedisCache Redis caches}
* on startup. The default {@link RedisCacheConfiguration} will be applied to each cache.
@@ -244,11 +243,11 @@ public RedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration d
/**
* Creates new {@link RedisCacheManager} using given {@link RedisCacheWriter} and default
* {@link RedisCacheConfiguration}.
- *
+ *
* Additionally, an initial {@link RedisCache} will be created and configured using the associated
* {@link RedisCacheConfiguration} for each {@link String named} {@link RedisCache} in the given {@link Map}.
- *
- * Allows cache creation at runtime.
+ *
+ * Allows {@link RedisCache cache} creation at runtime.
*
* @param cacheWriter {@link RedisCacheWriter} used to perform {@link RedisCache} operations
* by executing appropriate Redis commands; must not be {@literal null}.
@@ -271,7 +270,7 @@ public RedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration d
/**
* Creates a new {@link RedisCacheManager} initialized with the given {@link RedisCacheWriter}
* and a default {@link RedisCacheConfiguration}, and whether to allow {@link RedisCache} creation at runtime.
- *
+ *
* Additionally, an initial {@link RedisCache} will be created and configured using the associated
* {@link RedisCacheConfiguration} for each {@link String named} {@link RedisCache} in the given {@link Map}.
*
@@ -279,11 +278,11 @@ public RedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration d
* by executing appropriate Redis commands; must not be {@literal null}.
* @param defaultCacheConfiguration {@link RedisCacheConfiguration} applied to new {@link RedisCache Redis caches}
* by default when no cache-specific {@link RedisCacheConfiguration} is provided; must not be {@literal null}.
- * @param allowRuntimeCacheCreation boolean to allow creation of undeclared caches at runtime;
+ * @param allowRuntimeCacheCreation boolean specifying whether to allow creation of undeclared caches at runtime;
* {@literal true} by default. Maybe just use {@link RedisCacheConfiguration#defaultCacheConfig()}.
- * @param initialCacheConfigurations {@link Map} of declared, known {@link String cache names} along with associated
- * {@link RedisCacheConfiguration} used to create and configure {@link RedisCache Redis caches} on startup;
- * must not be {@literal null}.
+ * @param initialCacheConfigurations {@link Map} of declared, known {@link String cache names} along with
+ * the associated {@link RedisCacheConfiguration} used to create and configure {@link RedisCache Redis caches}
+ * on startup; must not be {@literal null}.
* @throws IllegalArgumentException if either the given {@link RedisCacheWriter} or {@link RedisCacheConfiguration}
* are {@literal null}.
* @see org.springframework.data.redis.cache.RedisCacheConfiguration
@@ -333,7 +332,8 @@ public Map
+ * {@link RedisCacheManager#getMissingCache(String)} returns {@literal null} for any non-configured, undeclared
+ * {@link Cache} instead of a new {@link RedisCache} instance. This allows the
* {@link org.springframework.cache.support.CompositeCacheManager} to participate.
*
* @return this {@link RedisCacheManagerBuilder}.
diff --git a/src/main/java/org/springframework/data/redis/cache/RedisCacheWriter.java b/src/main/java/org/springframework/data/redis/cache/RedisCacheWriter.java
index fb1adc6e46..3ad8426780 100644
--- a/src/main/java/org/springframework/data/redis/cache/RedisCacheWriter.java
+++ b/src/main/java/org/springframework/data/redis/cache/RedisCacheWriter.java
@@ -85,7 +85,9 @@ static RedisCacheWriter lockingRedisCacheWriter(RedisConnectionFactory connectio
*/
static RedisCacheWriter lockingRedisCacheWriter(RedisConnectionFactory connectionFactory,
BatchStrategy batchStrategy) {
- return lockingRedisCacheWriter(connectionFactory, Duration.ofMillis(50), TtlFunction.persistent(), batchStrategy);
+
+ return lockingRedisCacheWriter(connectionFactory, Duration.ofMillis(50), TtlFunction.persistent(),
+ batchStrategy);
}
/**
@@ -104,29 +106,44 @@ static RedisCacheWriter lockingRedisCacheWriter(RedisConnectionFactory connectio
Assert.notNull(connectionFactory, "ConnectionFactory must not be null");
- return new DefaultRedisCacheWriter(connectionFactory, sleepTime, lockTtlFunction, CacheStatisticsCollector.none(),
- batchStrategy);
+ return new DefaultRedisCacheWriter(connectionFactory, sleepTime, lockTtlFunction,
+ CacheStatisticsCollector.none(), batchStrategy);
}
/**
- * Write the given key/value pair to Redis and set the expiration time if defined.
+ * Get the binary value representation from Redis stored for the given key.
*
- * @param name The cache name must not be {@literal null}.
- * @param key The key for the cache entry. Must not be {@literal null}.
- * @param value The value stored for the key. Must not be {@literal null}.
- * @param ttl Optional expiration time. Can be {@literal null}.
+ * @param name must not be {@literal null}.
+ * @param key must not be {@literal null}.
+ * @return {@literal null} if key does not exist.
+ * @see #get(String, byte[], Duration)
*/
- void put(String name, byte[] key, byte[] value, @Nullable Duration ttl);
+ @Nullable
+ byte[] get(String name, byte[] key);
/**
- * Get the binary value representation from Redis stored for the given key.
+ * Get the binary value representation from Redis stored for the given key and set the given
+ * {@link Duration TTL expiration} for the cache entry.
*
* @param name must not be {@literal null}.
* @param key must not be {@literal null}.
- * @return {@literal null} if key does not exist.
+ * @param ttl {@link Duration} specifying the {@literal expiration timeout} for the cache entry.
+ * @return {@literal null} if key does not exist or has {@literal expired}.
*/
@Nullable
- byte[] get(String name, byte[] key);
+ default byte[] get(String name, byte[] key, @Nullable Duration ttl) {
+ return get(name, key);
+ }
+
+ /**
+ * Write the given key/value pair to Redis and set the expiration time if defined.
+ *
+ * @param name The cache name must not be {@literal null}.
+ * @param key The key for the cache entry. Must not be {@literal null}.
+ * @param value The value stored for the key. Must not be {@literal null}.
+ * @param ttl Optional expiration time. Can be {@literal null}.
+ */
+ void put(String name, byte[] key, byte[] value, @Nullable Duration ttl);
/**
* Write the given value to Redis if the key does not already exist.
diff --git a/src/main/java/org/springframework/data/redis/core/types/Expiration.java b/src/main/java/org/springframework/data/redis/core/types/Expiration.java
index f21b46f386..c5df3ae8f7 100644
--- a/src/main/java/org/springframework/data/redis/core/types/Expiration.java
+++ b/src/main/java/org/springframework/data/redis/core/types/Expiration.java
@@ -16,10 +16,12 @@
package org.springframework.data.redis.core.types;
import java.time.Duration;
+import java.util.Objects;
import java.util.concurrent.TimeUnit;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
+import org.springframework.util.ObjectUtils;
/**
* {@link Expiration} holds a {@link Long numeric value} with an associated {@link TimeUnit}.
@@ -219,6 +221,25 @@ public boolean isUnixTimestamp() {
return false;
}
+ @Override
+ public boolean equals(Object obj) {
+
+ if (this == obj) {
+ return true;
+ }
+
+ if (!(obj instanceof Expiration that)) {
+ return false;
+ }
+
+ return this.getTimeUnit().toMillis(getExpirationTime()) == that.getTimeUnit().toMillis(that.getExpirationTime());
+ }
+
+ @Override
+ public int hashCode() {
+ return ObjectUtils.nullSafeHashCode(new Object[] { getExpirationTime(), getTimeUnit() });
+ }
+
/**
* @author Christoph Strobl
* @since 2.4
diff --git a/src/test/java/org/springframework/data/redis/cache/DefaultRedisCacheWriterUnitTests.java b/src/test/java/org/springframework/data/redis/cache/DefaultRedisCacheWriterUnitTests.java
new file mode 100644
index 0000000000..47f79b7710
--- /dev/null
+++ b/src/test/java/org/springframework/data/redis/cache/DefaultRedisCacheWriterUnitTests.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2023 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.redis.cache;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import java.time.Duration;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import org.springframework.data.redis.connection.RedisConnection;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.types.Expiration;
+
+/**
+ * Unit tests for {@link DefaultRedisCacheWriter}
+ *
+ * @author John Blum
+ */
+@ExtendWith(MockitoExtension.class)
+class DefaultRedisCacheWriterUnitTests {
+
+ @Mock
+ private RedisConnection mockConnection;
+
+ @Mock
+ private RedisConnectionFactory mockConnectionFactory;
+
+ @BeforeEach
+ void setup() {
+ doReturn(this.mockConnection).when(this.mockConnectionFactory).getConnection();
+ }
+
+ private RedisCacheWriter newRedisCacheWriter() {
+ return new DefaultRedisCacheWriter(this.mockConnectionFactory, mock(BatchStrategy.class))
+ .withStatisticsCollector(mock(CacheStatisticsCollector.class));
+ }
+
+ @Test // GH-2351
+ void getWithNonNullTtl() {
+
+ byte[] key = "TestKey".getBytes();
+ byte[] value = "TestValue".getBytes();
+
+ Duration ttl = Duration.ofSeconds(15);
+ Expiration expiration = Expiration.from(ttl);
+
+ doReturn(value).when(this.mockConnection).getEx(any(), any());
+
+ RedisCacheWriter cacheWriter = newRedisCacheWriter();
+
+ assertThat(cacheWriter.get("TestCache", key, ttl)).isEqualTo(value);
+
+ verify(this.mockConnection, times(1)).getEx(eq(key), eq(expiration));
+ verify(this.mockConnection).close();
+ verifyNoMoreInteractions(this.mockConnection);
+ }
+
+ @Test // GH-2351
+ void getWithNullTtl() {
+
+ byte[] key = "TestKey".getBytes();
+ byte[] value = "TestValue".getBytes();
+
+ doReturn(value).when(this.mockConnection).get(any());
+
+ RedisCacheWriter cacheWriter = newRedisCacheWriter();
+
+ assertThat(cacheWriter.get("TestCache", key, null)).isEqualTo(value);
+
+ verify(this.mockConnection, times(1)).get(eq(key));
+ verify(this.mockConnection).close();
+ verifyNoMoreInteractions(this.mockConnection);
+ }
+}
diff --git a/src/test/java/org/springframework/data/redis/cache/RedisCacheConfigurationUnitTests.java b/src/test/java/org/springframework/data/redis/cache/RedisCacheConfigurationUnitTests.java
index 4f54eb1442..62ac41b055 100644
--- a/src/test/java/org/springframework/data/redis/cache/RedisCacheConfigurationUnitTests.java
+++ b/src/test/java/org/springframework/data/redis/cache/RedisCacheConfigurationUnitTests.java
@@ -75,7 +75,6 @@ void getTtlReturnsFixedDuration() {
RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(sixtySeconds);
-
assertThat(cacheConfiguration).isNotNull();
assertThat(cacheConfiguration.getTtl()).isEqualByComparingTo(sixtySeconds);
assertThat(cacheConfiguration.getTtl()).isEqualByComparingTo(sixtySeconds); // does not change!
@@ -83,7 +82,7 @@ void getTtlReturnsFixedDuration() {
@Test // GH-2628
@SuppressWarnings("deprecation")
- public void getTtlCanReturnDynamicDuration() {
+ public void getTtlReturnsDynamicDuration() {
Duration thirtyMinutes = Duration.ofMinutes(30);
Duration twoHours = Duration.ofHours(2);
@@ -102,6 +101,21 @@ public void getTtlCanReturnDynamicDuration() {
verifyNoMoreInteractions(mockTtlFunction);
}
+ @Test // GH-2351
+ public void enableTtiExpirationShouldConfigureTti() {
+
+ RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
+
+ assertThat(cacheConfiguration).isNotNull();
+ assertThat(cacheConfiguration.isTimeToIdleEnabled()).isFalse();
+
+ RedisCacheConfiguration ttiEnabledCacheConfiguration = cacheConfiguration.enableTimeToIdle();
+
+ assertThat(ttiEnabledCacheConfiguration).isNotNull();
+ assertThat(ttiEnabledCacheConfiguration).isNotSameAs(cacheConfiguration);
+ assertThat(ttiEnabledCacheConfiguration.isTimeToIdleEnabled()).isTrue();
+ }
+
private static class DomainType {
}
diff --git a/src/test/java/org/springframework/data/redis/cache/RedisCacheTests.java b/src/test/java/org/springframework/data/redis/cache/RedisCacheTests.java
index 326fc78a37..dc8da36954 100644
--- a/src/test/java/org/springframework/data/redis/cache/RedisCacheTests.java
+++ b/src/test/java/org/springframework/data/redis/cache/RedisCacheTests.java
@@ -15,10 +15,10 @@
*/
package org.springframework.data.redis.cache;
-import static org.assertj.core.api.Assertions.*;
-import static org.assertj.core.api.Assumptions.*;
-
-import io.netty.util.concurrent.DefaultThreadFactory;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
+import static org.assertj.core.api.Assumptions.assumeThat;
+import static org.awaitility.Awaitility.await;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
@@ -34,9 +34,11 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
+import java.util.function.Function;
import java.util.stream.IntStream;
import org.junit.jupiter.api.BeforeEach;
+
import org.springframework.cache.Cache.ValueWrapper;
import org.springframework.cache.interceptor.SimpleKey;
import org.springframework.cache.interceptor.SimpleKeyGenerator;
@@ -46,10 +48,13 @@
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.serializer.RedisSerializationContext.SerializationPair;
import org.springframework.data.redis.serializer.RedisSerializer;
+import org.springframework.data.redis.test.condition.EnabledOnCommand;
import org.springframework.data.redis.test.extension.parametrized.MethodSource;
import org.springframework.data.redis.test.extension.parametrized.ParameterizedRedisTest;
import org.springframework.lang.Nullable;
+import io.netty.util.concurrent.DefaultThreadFactory;
+
/**
* Tests for {@link RedisCache} with {@link DefaultRedisCacheWriter} using different {@link RedisSerializer} and
* {@link RedisConnectionFactory} pairs.
@@ -92,8 +97,22 @@ void setUp() {
doWithConnection(RedisConnection::flushAll);
- cache = new RedisCache("cache", RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory),
- RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(SerializationPair.fromSerializer(serializer)));
+ this.cache = new RedisCache("cache", usingRedisCacheWriter(), usingRedisCacheConfiguration());
+ }
+
+ private RedisCacheWriter usingRedisCacheWriter() {
+ return RedisCacheWriter.nonLockingRedisCacheWriter(this.connectionFactory);
+ }
+
+ private RedisCacheConfiguration usingRedisCacheConfiguration() {
+ return usingRedisCacheConfiguration(Function.identity());
+ }
+
+ private RedisCacheConfiguration usingRedisCacheConfiguration(
+ Function
*