package com.rdj.distributelock;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
public class DistributeLockApplication {
public static void main(String[] args) {
SpringApplication.run(DistributeLockApplication.class, args);
}
}
//service
package com.rdj.distributelock.service;
import com.rdj.distributelock.lock.RedisLock;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
/**
* redis 分布式鎖實現定時任務
*/
@Service
@Slf4j
public class SchedulerService {
@Autowired
private RedisTemplate redisTemplate;
//模擬每隔5秒執行一次
@Scheduled(cron = "*/5 * * * * ?")
public void sendSms(){
try(RedisLock redisLock = new RedisLock(redisTemplate,"autoSms",30)) {
if (redisLock.getLock()) {
//獲取到鎖,才執行定時任務
log.info("發送短信");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.rdj.distributelock.lock;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.data.redis.core.types.Expiration;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
//AutoCloseable jdk1.7 后增加的 自動關閉特性
@Slf4j
public class RedisLock implements AutoCloseable{
private RedisTemplate redisTemplate;
private String key;
private String value;
private int expireTime;//過期時間,單位秒
public RedisLock(RedisTemplate redisTemplate, String key,int expireTime){
this.redisTemplate = redisTemplate;
this.key = key;
this.expireTime = expireTime;
this.value = UUID.randomUUID().toString();
}
/**
* 獲取分布式鎖
* @return
*/
public boolean getLock(){
RedisCallback<Boolean> redisCallback = connection -> {
RedisStringCommands.SetOption setOption = RedisStringCommands.SetOption.ifAbsent();
Expiration expiration = Expiration.seconds(expireTime);
byte[] redisKey = redisTemplate.getKeySerializer().serialize(key);
byte[] redisValue = redisTemplate.getKeySerializer().serialize(value);
Boolean result = connection.set(redisKey, redisValue, expiration, setOption);
return result;
};
boolean lock = (boolean) redisTemplate.execute(redisCallback);
return lock;
}
public boolean unLock(){
String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then\n" +
" return redis.call(\"del\",KEYS[1])\n" +
"else\n" +
" return 0\n" +
"end";
RedisScript<Boolean> redisScript = RedisScript.of(script,Boolean.class);
List<String> keys = Arrays.asList(key);
Boolean res = (Boolean) redisTemplate.execute(redisScript, keys, value);
log.info("釋放鎖的結果 {}",res);
return res;
}
@Override
public void close() throws Exception {
unLock();
}
}