2424import org .springframework .util .Assert ;
2525
2626/**
27- * {@link RedisCacheWriter} provides low-level access to Redis commands ({@code SET, SETNX, GET, EXPIRE,...})
28- * used for caching.
27+ * {@link RedisCacheWriter} provides low-level access to Redis commands ({@code SET, SETNX, GET, EXPIRE,...}) used for
28+ * caching.
2929 * <p>
3030 * The {@link RedisCacheWriter} may be shared by multiple cache implementations and is responsible for reading/writing
3131 * binary data from/to Redis. The implementation honors potential cache lock flags that might be set.
3232 * <p>
33- * The default {@link RedisCacheWriter} implementation can be customized with {@link BatchStrategy}
34- * to tune performance behavior.
33+ * The default {@link RedisCacheWriter} implementation can be customized with {@link BatchStrategy} to tune performance
34+ * behavior.
3535 *
3636 * @author Christoph Strobl
3737 * @author Mark Paluch
@@ -96,9 +96,8 @@ static RedisCacheWriter lockingRedisCacheWriter(RedisConnectionFactory connectio
9696 *
9797 * @param connectionFactory must not be {@literal null}.
9898 * @param sleepTime sleep time between lock access attempts, must not be {@literal null}.
99- * @param lockTtlFunction TTL function to compute the Lock TTL. The function is called with contextual keys
100- * and values (such as the cache name on cleanup or the actual key/value on put requests);
101- * must not be {@literal null}.
99+ * @param lockTtlFunction TTL function to compute the Lock TTL. The function is called with contextual keys and values
100+ * (such as the cache name on cleanup or the actual key/value on put requests); must not be {@literal null}.
102101 * @param batchStrategy must not be {@literal null}.
103102 * @return new instance of {@link DefaultRedisCacheWriter}.
104103 * @since 3.2
@@ -124,8 +123,8 @@ static RedisCacheWriter lockingRedisCacheWriter(RedisConnectionFactory connectio
124123 byte [] get (String name , byte [] key );
125124
126125 /**
127- * Get the binary value representation from Redis stored for the given key and set
128- * the given {@link Duration TTL expiration} for the cache entry.
126+ * Get the binary value representation from Redis stored for the given key and set the given {@link Duration TTL
127+ * expiration} for the cache entry.
129128 *
130129 * @param name must not be {@literal null}.
131130 * @param key must not be {@literal null}.
@@ -138,14 +137,41 @@ default byte[] get(String name, byte[] key, @Nullable Duration ttl) {
138137 }
139138
140139 /**
141- * Determines whether the asynchronous {@link #retrieve(String, byte[])}
142- * and {@link #retrieve(String, byte[], Duration)} cache operations are supported by the implementation .
140+ * Get the binary value representation from Redis stored for the given key and set the given {@link Duration TTL
141+ * expiration} for the cache entry, obtaining the value from {@code valueLoader} if necessary .
143142 * <p>
144- * The main factor for whether the {@literal retrieve} operation can be supported will primarily be determined
145- * by the Redis driver in use at runtime.
143+ * If possible (and configured for locking), implementations should ensure that the loading operation is synchronized
144+ * so that the specified {@code valueLoader} is only called once in case of concurrent access on the same key.
145+ *
146+ * @param name must not be {@literal null}.
147+ * @param key must not be {@literal null}.
148+ * @param valueLoader value loader that creates the value if the cache lookup has been not successful.
149+ * @param ttl {@link Duration} specifying the {@literal expiration timeout} for the cache entry.
150+ * @param timeToIdleEnabled {@literal true} to enable Time to Idle when retrieving the value.
151+ * @since 3.4
152+ */
153+ default byte [] get (String name , byte [] key , Supplier <byte []> valueLoader , @ Nullable Duration ttl ,
154+ boolean timeToIdleEnabled ) {
155+
156+ byte [] bytes = timeToIdleEnabled ? get (name , key , ttl ) : get (name , key );
157+
158+ if (bytes == null ) {
159+ bytes = valueLoader .get ();
160+ put (name , key , bytes , ttl );
161+ }
162+
163+ return bytes ;
164+ }
165+
166+ /**
167+ * Determines whether the asynchronous {@link #retrieve(String, byte[])} and
168+ * {@link #retrieve(String, byte[], Duration)} cache operations are supported by the implementation.
169+ * <p>
170+ * The main factor for whether the {@literal retrieve} operation can be supported will primarily be determined by the
171+ * Redis driver in use at runtime.
146172 * <p>
147- * Returns {@literal false} by default. This will have an effect of {@link RedisCache#retrieve(Object)}
148- * and {@link RedisCache#retrieve(Object, Supplier)} throwing an {@link UnsupportedOperationException}.
173+ * Returns {@literal false} by default. This will have an effect of {@link RedisCache#retrieve(Object)} and
174+ * {@link RedisCache#retrieve(Object, Supplier)} throwing an {@link UnsupportedOperationException}.
149175 *
150176 * @return {@literal true} if asynchronous {@literal retrieve} operations are supported by the implementation.
151177 * @since 3.2
@@ -155,8 +181,8 @@ default boolean supportsAsyncRetrieve() {
155181 }
156182
157183 /**
158- * Asynchronously retrieves the {@link CompletableFuture value} to which the {@link RedisCache}
159- * maps the given {@link byte[] key}.
184+ * Asynchronously retrieves the {@link CompletableFuture value} to which the {@link RedisCache} maps the given
185+ * {@link byte[] key}.
160186 * <p>
161187 * This operation is non-blocking.
162188 *
@@ -171,8 +197,8 @@ default CompletableFuture<byte[]> retrieve(String name, byte[] key) {
171197 }
172198
173199 /**
174- * Asynchronously retrieves the {@link CompletableFuture value} to which the {@link RedisCache} maps
175- * the given {@link byte[] key} setting the {@link Duration TTL expiration} for the cache entry.
200+ * Asynchronously retrieves the {@link CompletableFuture value} to which the {@link RedisCache} maps the given
201+ * {@link byte[] key} setting the {@link Duration TTL expiration} for the cache entry.
176202 * <p>
177203 * This operation is non-blocking.
178204 *
@@ -264,8 +290,8 @@ interface TtlFunction {
264290 /**
265291 * Creates a {@literal Singleton} {@link TtlFunction} using the given {@link Duration}.
266292 *
267- * @param duration the time to live. Can be {@link Duration#ZERO} for persistent values (i.e. cache entry
268- * does not expire).
293+ * @param duration the time to live. Can be {@link Duration#ZERO} for persistent values (i.e. cache entry does not
294+ * expire).
269295 * @return a singleton {@link TtlFunction} using {@link Duration}.
270296 */
271297 static TtlFunction just (Duration duration ) {
0 commit comments