Skip to content

Commit 248b846

Browse files
committed
spring-projectsGH-3805: fix javadoc, convention, lazy init
1 parent 1306c9c commit 248b846

File tree

2 files changed

+68
-62
lines changed

2 files changed

+68
-62
lines changed

spring-integration-redis/src/main/java/org/springframework/integration/redis/util/RedisLockRegistry.java

Lines changed: 67 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import java.util.LinkedHashMap;
2323
import java.util.Map;
2424
import java.util.Map.Entry;
25-
import java.util.Objects;
2625
import java.util.UUID;
2726
import java.util.concurrent.ConcurrentHashMap;
2827
import java.util.concurrent.ExecutionException;
@@ -37,8 +36,6 @@
3736
import java.util.concurrent.locks.ReentrantLock;
3837
import java.util.function.Function;
3938

40-
import javax.annotation.Nonnull;
41-
4239
import org.apache.commons.logging.Log;
4340
import org.apache.commons.logging.LogFactory;
4441

@@ -54,6 +51,7 @@
5451
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
5552
import org.springframework.data.redis.listener.Topic;
5653
import org.springframework.integration.support.locks.ExpirableLockRegistry;
54+
import org.springframework.lang.NonNull;
5755
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
5856
import org.springframework.util.Assert;
5957
import org.springframework.util.ReflectionUtils;
@@ -117,10 +115,6 @@ protected boolean removeEldestEntry(Entry<String, RedisLock> eldest) {
117115

118116
private final StringRedisTemplate redisTemplate;
119117

120-
private final RedisUnLockNotifyMessageListener unlockNotifyMessageListener;
121-
122-
private final RedisMessageListenerContainer redisMessageListenerContainer;
123-
124118
private final long expireAfter;
125119

126120
private int cacheCapacity = DEFAULT_CAPACITY;
@@ -141,8 +135,18 @@ protected boolean removeEldestEntry(Entry<String, RedisLock> eldest) {
141135
private boolean executorExplicitlySet;
142136

143137
private volatile boolean unlinkAvailable = true;
138+
144139
private volatile boolean isRunningRedisMessageListenerContainer = false;
145140

141+
/**
142+
* It is set via lazy initialization when it is a {@link RedisLockType#PUB_SUB_LOCK}.
143+
*/
144+
private volatile RedisUnLockNotifyMessageListener unlockNotifyMessageListener;
145+
/**
146+
* It is set via lazy initialization when it is a {@link RedisLockType#PUB_SUB_LOCK}.
147+
*/
148+
private volatile RedisMessageListenerContainer redisMessageListenerContainer;
149+
146150
/**
147151
* Constructs a lock registry with the default (60 second) lock expiration.
148152
* @param connectionFactory The connection factory.
@@ -165,12 +169,13 @@ public RedisLockRegistry(RedisConnectionFactory connectionFactory, String regist
165169
this.registryKey = registryKey;
166170
this.expireAfter = expireAfter;
167171
this.unLockChannelKey = registryKey + "-channel";
168-
this.unlockNotifyMessageListener = new RedisUnLockNotifyMessageListener();
169-
this.redisMessageListenerContainer = new RedisMessageListenerContainer();
170-
setupUnlockMessageListener(connectionFactory);
171172
}
172173

173174
private void setupUnlockMessageListener(RedisConnectionFactory connectionFactory) {
175+
Assert.isNull(RedisLockRegistry.this.redisMessageListenerContainer, "'redisMessageListenerContainer' must not have been re-initialized.");
176+
Assert.isNull(RedisLockRegistry.this.unlockNotifyMessageListener, "'unlockNotifyMessageListener' must not have been re-initialized.");
177+
RedisLockRegistry.this.redisMessageListenerContainer = new RedisMessageListenerContainer();
178+
RedisLockRegistry.this.unlockNotifyMessageListener = new RedisUnLockNotifyMessageListener();
174179
final Topic topic = new ChannelTopic(this.unLockChannelKey);
175180
this.redisMessageListenerContainer.setConnectionFactory(connectionFactory);
176181
this.redisMessageListenerContainer.setTaskExecutor(this.executor);
@@ -200,19 +205,23 @@ public void setCacheCapacity(int cacheCapacity) {
200205
this.cacheCapacity = cacheCapacity;
201206
}
202207

208+
203209
/**
204-
* The default is {@link RedisLockType.SPIN_LOCK}<br>
205-
* {@link RedisLockType.SPIN_LOCK}: The lock is acquired by periodically(100ms) checking whether the lock can be acquired.<br>
206-
* {@link RedisLockType.PUB_SUB_LOCK}: The lock is accuired by redis pub-sub. <br>
207-
*
208-
* Set the type of unlockType
209-
* Select the lock method.
210+
* <p>
211+
* Because pub-sub does not work in some settings(RedisStaticMasterReplicaConfiguration), The default is {@link RedisLockType.SPIN_LOCK}
212+
* <ul>
213+
* <li>{@link RedisLockType#SPIN_LOCK}: The lock is acquired by periodically(100ms) checking whether the lock can be acquired.</li>
214+
* <li>{@link RedisLockType#PUB_SUB_LOCK}: The lock is accuired by redis pub-sub.</li>
215+
* </ul>
216+
* <p>
217+
* Set the type of unlockType, Select the lock method.
210218
*
211219
* @param redisLockType obtain RedisLockType
212-
* @since 6.0.0
220+
* @since 5.5.13
213221
*/
214-
public void setRedisLockType(@Nonnull RedisLockType redisLockType) {
215-
this.redisLockType = Objects.requireNonNull(redisLockType);
222+
public void setRedisLockType(@NonNull RedisLockType redisLockType) {
223+
Assert.notNull(redisLockType, "'redisLockType' cannot be null");
224+
this.redisLockType = redisLockType;
216225
}
217226

218227
@Override
@@ -253,7 +262,7 @@ public enum RedisLockType {
253262
PUB_SUB_LOCK, SPIN_LOCK;
254263
}
255264

256-
private Function<String, RedisLock> getRedisLockConstructor(@Nonnull RedisLockType redisLockType) {
265+
private Function<String, RedisLock> getRedisLockConstructor(@NonNull RedisLockType redisLockType) {
257266
return switch (redisLockType) {
258267
case PUB_SUB_LOCK -> RedisPubSubLock::new;
259268
case SPIN_LOCK -> RedisSpinLock::new;
@@ -262,6 +271,20 @@ private Function<String, RedisLock> getRedisLockConstructor(@Nonnull RedisLockTy
262271

263272

264273
private abstract class RedisLock implements Lock {
274+
275+
private static final String OBTAIN_LOCK_SCRIPT =
276+
"local lockClientId = redis.call('GET', KEYS[1])\n" +
277+
"if lockClientId == ARGV[1] then\n" +
278+
" redis.call('PEXPIRE', KEYS[1], ARGV[2])\n" +
279+
" return true\n" +
280+
"elseif not lockClientId then\n" +
281+
" redis.call('SET', KEYS[1], ARGV[1], 'PX', ARGV[2])\n" +
282+
" return true\n" +
283+
"end\n" +
284+
"return false";
285+
286+
protected static final RedisScript<Boolean> obtainLockScript = new DefaultRedisScript<>(OBTAIN_LOCK_SCRIPT, Boolean.class);
287+
265288
protected final String lockKey;
266289

267290
private final ReentrantLock localLock = new ReentrantLock();
@@ -385,6 +408,13 @@ private boolean tryRedisLock(long time) throws ExecutionException, InterruptedEx
385408
return result;
386409
}
387410

411+
protected Boolean obtainLock() {
412+
return RedisLockRegistry.this.redisTemplate
413+
.execute(obtainLockScript, Collections.singletonList(this.lockKey),
414+
RedisLockRegistry.this.clientId,
415+
String.valueOf(RedisLockRegistry.this.expireAfter));
416+
}
417+
388418
@Override
389419
public final void unlock() {
390420
if (!this.localLock.isHeldByCurrentThread()) {
@@ -495,19 +525,10 @@ public boolean equals(Object obj) {
495525
private RedisLockRegistry getOuterType() {
496526
return RedisLockRegistry.this;
497527
}
528+
498529
}
499530

500531
private final class RedisPubSubLock extends RedisLock {
501-
private static final String OBTAIN_LOCK_SCRIPT =
502-
"local lockClientId = redis.call('GET', KEYS[1])\n" +
503-
"if lockClientId == ARGV[1] then\n" +
504-
" redis.call('PEXPIRE', KEYS[1], ARGV[2])\n" +
505-
" return true\n" +
506-
"elseif not lockClientId then\n" +
507-
" redis.call('SET', KEYS[1], ARGV[1], 'PX', ARGV[2])\n" +
508-
" return true\n" +
509-
"end\n" +
510-
"return false";
511532

512533
private static final String UNLINK_UNLOCK_SCRIPT =
513534
"if (redis.call('unlink', KEYS[1]) == 1) then " +
@@ -522,9 +543,10 @@ private final class RedisPubSubLock extends RedisLock {
522543
"return true " +
523544
"end " +
524545
"return false";
525-
private final RedisScript<Boolean> obtainLockScript = new DefaultRedisScript<>(OBTAIN_LOCK_SCRIPT, Boolean.class);
526-
private final RedisScript<Boolean> unLinkUnLockScript = new DefaultRedisScript<>(UNLINK_UNLOCK_SCRIPT, Boolean.class);
527-
private final RedisScript<Boolean> deleteUnLockScript = new DefaultRedisScript<>(DELETE_UNLOCK_SCRIPT, Boolean.class);
546+
547+
private static final RedisScript<Boolean> unLinkUnLockScript = new DefaultRedisScript<>(UNLINK_UNLOCK_SCRIPT, Boolean.class);
548+
549+
private static final RedisScript<Boolean> deleteUnLockScript = new DefaultRedisScript<>(DELETE_UNLOCK_SCRIPT, Boolean.class);
528550

529551
private RedisPubSubLock(String path) {
530552
super(path);
@@ -538,14 +560,14 @@ protected boolean tryRedisLockInner(long time) throws ExecutionException, Interr
538560
@Override
539561
protected void removeLockKeyInnerUnlink() {
540562
RedisLockRegistry.this.redisTemplate.execute(
541-
this.unLinkUnLockScript, Collections.singletonList(this.lockKey),
563+
unLinkUnLockScript, Collections.singletonList(this.lockKey),
542564
RedisLockRegistry.this.unLockChannelKey);
543565
}
544566

545567
@Override
546568
protected void removeLockKeyInnerDelete() {
547569
RedisLockRegistry.this.redisTemplate.execute(
548-
this.deleteUnLockScript, Collections.singletonList(this.lockKey),
570+
deleteUnLockScript, Collections.singletonList(this.lockKey),
549571
RedisLockRegistry.this.unLockChannelKey);
550572

551573
}
@@ -557,6 +579,7 @@ private boolean subscribeLock(long time) throws ExecutionException, InterruptedE
557579
}
558580

559581
if (!(RedisLockRegistry.this.isRunningRedisMessageListenerContainer
582+
&& RedisLockRegistry.this.redisMessageListenerContainer != null
560583
&& RedisLockRegistry.this.redisMessageListenerContainer.isRunning())) {
561584
runRedisMessageListenerContainer();
562585
}
@@ -586,23 +609,23 @@ private boolean subscribeLock(long time) throws ExecutionException, InterruptedE
586609
return false;
587610
}
588611

589-
private Boolean obtainLock() {
590-
return RedisLockRegistry.this.redisTemplate
591-
.execute(this.obtainLockScript, Collections.singletonList(this.lockKey),
592-
RedisLockRegistry.this.clientId,
593-
String.valueOf(RedisLockRegistry.this.expireAfter));
594-
}
595-
596612
private void runRedisMessageListenerContainer() {
597-
synchronized (RedisLockRegistry.this.redisMessageListenerContainer) {
613+
synchronized (RedisLockRegistry.this.locks) {
598614
if (!(RedisLockRegistry.this.isRunningRedisMessageListenerContainer
615+
&& RedisLockRegistry.this.redisMessageListenerContainer != null
599616
&& RedisLockRegistry.this.redisMessageListenerContainer.isRunning())) {
600-
RedisLockRegistry.this.redisMessageListenerContainer.afterPropertiesSet();
617+
618+
if (RedisLockRegistry.this.redisMessageListenerContainer == null) {
619+
setupUnlockMessageListener(RedisLockRegistry.this.redisTemplate.getConnectionFactory());
620+
RedisLockRegistry.this.redisMessageListenerContainer.afterPropertiesSet();
621+
}
622+
601623
RedisLockRegistry.this.redisMessageListenerContainer.start();
602624
RedisLockRegistry.this.isRunningRedisMessageListenerContainer = true;
603625
}
604626
}
605627
}
628+
606629
}
607630

608631
/**
@@ -636,17 +659,6 @@ private void unlockNotify(String lockKey) {
636659
}
637660

638661
private final class RedisSpinLock extends RedisLock {
639-
private static final String OBTAIN_LOCK_SCRIPT =
640-
"local lockClientId = redis.call('GET', KEYS[1])\n" +
641-
"if lockClientId == ARGV[1] then\n" +
642-
" redis.call('PEXPIRE', KEYS[1], ARGV[2])\n" +
643-
" return true\n" +
644-
"elseif not lockClientId then\n" +
645-
" redis.call('SET', KEYS[1], ARGV[1], 'PX', ARGV[2])\n" +
646-
" return true\n" +
647-
"end\n" +
648-
"return false";
649-
private final RedisScript<Boolean> obtainLockScript = new DefaultRedisScript<>(OBTAIN_LOCK_SCRIPT, Boolean.class);
650662

651663
private RedisSpinLock(String path) {
652664
super(path);
@@ -681,12 +693,5 @@ protected void removeLockKeyInnerDelete() {
681693
RedisLockRegistry.this.redisTemplate.delete(this.lockKey);
682694
}
683695

684-
private boolean obtainLock() {
685-
return RedisLockRegistry.this.redisTemplate
686-
.execute(this.obtainLockScript,
687-
Collections.singletonList(this.lockKey),
688-
RedisLockRegistry.this.clientId,
689-
String.valueOf(RedisLockRegistry.this.expireAfter));
690-
}
691696
}
692697
}

spring-integration-redis/src/test/java/org/springframework/integration/redis/util/RedisLockRegistryTests.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -832,4 +832,5 @@ private void waitForExpire(String key) throws Exception {
832832
private static Map<String, Lock> getRedisLockRegistryLocks(RedisLockRegistry registry) {
833833
return TestUtils.getPropertyValue(registry, "locks", Map.class);
834834
}
835+
835836
}

0 commit comments

Comments
 (0)