@@ -84,6 +84,8 @@ class DefaultRedisCacheWriter implements RedisCacheWriter {
8484
8585 private final AsyncCacheWriter asyncCacheWriter ;
8686
87+ private final boolean asynchronousWrites ;
88+
8789 /**
8890 * @param connectionFactory must not be {@literal null}.
8991 * @param batchStrategy must not be {@literal null}.
@@ -99,19 +101,11 @@ class DefaultRedisCacheWriter implements RedisCacheWriter {
99101 * @param batchStrategy must not be {@literal null}.
100102 */
101103 DefaultRedisCacheWriter (RedisConnectionFactory connectionFactory , Duration sleepTime , BatchStrategy batchStrategy ) {
102- this (connectionFactory , sleepTime , TtlFunction .persistent (), CacheStatisticsCollector .none (), batchStrategy );
104+ this (connectionFactory , sleepTime , TtlFunction .persistent (), CacheStatisticsCollector .none (), batchStrategy , true );
103105 }
104106
105- /**
106- * @param connectionFactory must not be {@literal null}.
107- * @param sleepTime sleep time between lock request attempts. Must not be {@literal null}. Use {@link Duration#ZERO}
108- * to disable locking.
109- * @param lockTtl Lock TTL function must not be {@literal null}.
110- * @param cacheStatisticsCollector must not be {@literal null}.
111- * @param batchStrategy must not be {@literal null}.
112- */
113107 DefaultRedisCacheWriter (RedisConnectionFactory connectionFactory , Duration sleepTime , TtlFunction lockTtl ,
114- CacheStatisticsCollector cacheStatisticsCollector , BatchStrategy batchStrategy ) {
108+ CacheStatisticsCollector cacheStatisticsCollector , BatchStrategy batchStrategy , boolean asynchronousWrites ) {
115109
116110 Assert .notNull (connectionFactory , "ConnectionFactory must not be null" );
117111 Assert .notNull (sleepTime , "SleepTime must not be null" );
@@ -126,12 +120,116 @@ class DefaultRedisCacheWriter implements RedisCacheWriter {
126120 this .batchStrategy = batchStrategy ;
127121
128122 if (REACTIVE_REDIS_CONNECTION_FACTORY_PRESENT && this .connectionFactory instanceof ReactiveRedisConnectionFactory ) {
129- asyncCacheWriter = new AsynchronousCacheWriterDelegate ();
123+ this .asyncCacheWriter = new AsynchronousCacheWriterDelegate ();
124+ this .asynchronousWrites = asynchronousWrites ;
130125 } else {
131126 asyncCacheWriter = UnsupportedAsyncCacheWriter .INSTANCE ;
127+ this .asynchronousWrites = false ;
132128 }
133129 }
134130
131+ /**
132+ * Create a new {@code DefaultRedisCacheWriter} applying configuration through {@code configurerConsumer}.
133+ *
134+ * @param connectionFactory the connection factory to use.
135+ * @param configurerConsumer configuration consumer.
136+ * @return a new {@code DefaultRedisCacheWriter}.
137+ * @since 4.0
138+ */
139+ public static DefaultRedisCacheWriter create (RedisConnectionFactory connectionFactory ,
140+ Consumer <RedisCacheWriterConfigurer > configurerConsumer ) {
141+
142+ Assert .notNull (connectionFactory , "RedisConnectionFactory must not be null" );
143+ Assert .notNull (configurerConsumer , "RedisCacheWriterConfigurer function must not be null" );
144+
145+ DefaultRedisCacheWriterConfigurer config = new DefaultRedisCacheWriterConfigurer ();
146+ configurerConsumer .accept (config );
147+
148+ return new DefaultRedisCacheWriter (connectionFactory , config .lockSleepTime , config .lockTtlFunction ,
149+ config .cacheStatisticsCollector , config .batchStrategy , !config .immediateWrites );
150+ }
151+
152+ static class DefaultRedisCacheWriterConfigurer
153+ implements RedisCacheWriterConfigurer , CacheLockingConfigurer , CacheLockingConfiguration {
154+
155+ CacheStatisticsCollector cacheStatisticsCollector = CacheStatisticsCollector .none ();
156+ BatchStrategy batchStrategy = BatchStrategies .keys ();
157+ Duration lockSleepTime = Duration .ZERO ;
158+ TtlFunction lockTtlFunction = TtlFunction .persistent ();
159+ boolean immediateWrites = false ;
160+
161+ @ Override
162+ public RedisCacheWriterConfigurer collectStatistics (CacheStatisticsCollector cacheStatisticsCollector ) {
163+
164+ Assert .notNull (cacheStatisticsCollector , "CacheStatisticsCollector must not be null" );
165+ this .cacheStatisticsCollector = cacheStatisticsCollector ;
166+
167+ return this ;
168+ }
169+
170+ @ Override
171+ public RedisCacheWriterConfigurer batchStrategy (BatchStrategy batchStrategy ) {
172+
173+ Assert .notNull (batchStrategy , "BatchStrategy must not be null" );
174+ this .batchStrategy = batchStrategy ;
175+
176+ return this ;
177+ }
178+
179+ @ Override
180+ public RedisCacheWriterConfigurer cacheLocking (Consumer <CacheLockingConfigurer > configurerConsumer ) {
181+
182+ Assert .notNull (configurerConsumer , "CacheLockingConfigurer function must not be null" );
183+ configurerConsumer .accept (this );
184+
185+ return this ;
186+ }
187+
188+ @ Override
189+ public RedisCacheWriterConfigurer immediateWrites (boolean enableImmediateWrites ) {
190+
191+ this .immediateWrites = enableImmediateWrites ;
192+ return this ;
193+ }
194+
195+ @ Override
196+ public void disable () {
197+ this .lockSleepTime = Duration .ZERO ;
198+ }
199+
200+ @ Override
201+ public void enable (Consumer <CacheLockingConfiguration > configurationConsumer ) {
202+
203+ Assert .notNull (configurationConsumer , "CacheLockingConfigurer function must not be null" );
204+
205+ if (this .lockSleepTime .isZero () || this .lockSleepTime .isNegative ()) {
206+ this .lockSleepTime = Duration .ofMillis (50 );
207+ }
208+ configurationConsumer .accept (this );
209+ }
210+
211+ @ Override
212+ public CacheLockingConfiguration sleepTime (Duration sleepTime ) {
213+
214+ Assert .notNull (sleepTime , "Lock sleep time must not be null" );
215+ Assert .isTrue (!sleepTime .isZero () && !sleepTime .isNegative (),
216+ "Lock sleep time must not be null zero or negative" );
217+
218+ this .lockSleepTime = sleepTime ;
219+ return this ;
220+ }
221+
222+ @ Override
223+ public CacheLockingConfiguration lockTimeout (TtlFunction ttlFunction ) {
224+
225+ Assert .notNull (ttlFunction , "TTL function must not be null" );
226+
227+ this .lockTtlFunction = ttlFunction ;
228+ return this ;
229+ }
230+
231+ }
232+
135233 @ Override
136234 public byte @ Nullable [] get (String name , byte [] key ) {
137235 return get (name , key , null );
@@ -210,6 +308,10 @@ public boolean supportsAsyncRetrieve() {
210308 return asyncCacheWriter .isSupported ();
211309 }
212310
311+ private boolean writeAsynchronously () {
312+ return supportsAsyncRetrieve () && asynchronousWrites ;
313+ }
314+
213315 @ Override
214316 public CompletableFuture <byte []> retrieve (String name , byte [] key , @ Nullable Duration ttl ) {
215317
@@ -238,7 +340,7 @@ public void put(String name, byte[] key, byte[] value, @Nullable Duration ttl) {
238340 Assert .notNull (key , "Key must not be null" );
239341 Assert .notNull (value , "Value must not be null" );
240342
241- if (supportsAsyncRetrieve ()) {
343+ if (writeAsynchronously ()) {
242344 asyncCacheWriter .store (name , key , value , ttl ).thenRun (() -> statistics .incPuts (name ));
243345 } else {
244346 execute (name , connection -> {
@@ -318,7 +420,7 @@ public void remove(String name, byte[] key) {
318420 Assert .notNull (name , "Name must not be null" );
319421 Assert .notNull (key , "Key must not be null" );
320422
321- if (supportsAsyncRetrieve ()) {
423+ if (writeAsynchronously ()) {
322424 asyncCacheWriter .remove (name , key ).thenRun (() -> statistics .incDeletes (name ));
323425 } else {
324426 removeIfPresent (name , key );
@@ -340,7 +442,7 @@ public void clean(String name, byte[] pattern) {
340442 Assert .notNull (name , "Name must not be null" );
341443 Assert .notNull (pattern , "Pattern must not be null" );
342444
343- if (supportsAsyncRetrieve ()) {
445+ if (writeAsynchronously ()) {
344446 asyncCacheWriter .clean (name , pattern , batchStrategy )
345447 .thenAccept (deleteCount -> statistics .incDeletesBy (name , deleteCount .intValue ()));
346448 return ;
@@ -393,7 +495,7 @@ public void clearStatistics(String name) {
393495 @ Override
394496 public RedisCacheWriter withStatisticsCollector (CacheStatisticsCollector cacheStatisticsCollector ) {
395497 return new DefaultRedisCacheWriter (connectionFactory , sleepTime , lockTtl , cacheStatisticsCollector ,
396- this .batchStrategy );
498+ this .batchStrategy , this . asynchronousWrites );
397499 }
398500
399501 /**
0 commit comments