SpringCloud定時任務需要用redis實現分散式全域性鎖的相關操作
阿新 • • 發佈:2019-01-07
我們知道現在微服務很流行,為此,許多中小型企業都將自己以前的框架加以改造,其中以SpringCloud為最多,但是SpringCloud如果要加定時任務的話,在單臺伺服器上很好支援,但是涉及到叢集服務(多臺服務的話)就要用到分散式鎖了,最簡單的方案是用Redis,好了廢話不多說,直接上程式碼.
第一步:在配置檔案application.properties中加入Redis的相關配置:
# REDIS (RedisProperties) # Redis資料庫索引(預設為0) spring.redis.database=0 # Redis伺服器地址 spring.redis.host=localhost # Redis伺服器連線埠 spring.redis.port=6379 # Redis伺服器連線密碼(預設為空) spring.redis.password=
第二步:新增jar包依賴,這裡以maven為例,pom.xml中加入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
第三部:redis工具類的寫法
1):新建Lock.java實體類
/** * 全域性鎖,包括鎖的名稱 Created by zuoguobin on 2017/4/1. */ public class Lock { private String name; private String value; public Lock(String name, String value) { this.name = name; this.value = value; } public String getName() { return name; } public String getValue() { return value; } }
2):新建DistributedLockHandler.java分散式鎖工具類,此時注意:@Component的寫法,目的是為了注入值
/** * Created by zuoguobin on 2017/4/1. */ @Component public class DistributedLockHandler { private static final Logger logger = LoggerFactory.getLogger(DistributedLockHandler.class); private final static long LOCK_EXPIRE = 30 * 1000L;// 單個業務持有鎖的時間30s,防止死鎖 private final static long LOCK_TRY_INTERVAL = 30L;// 預設30ms嘗試一次 private final static long LOCK_TRY_TIMEOUT = 20 * 1000L;// 預設嘗試20s @Autowired private StringRedisTemplate template; /** * 嘗試獲取全域性鎖 * * @param lock * 鎖的名稱 * @return true 獲取成功,false獲取失敗 */ public boolean tryLock(Lock lock) { return getLock(lock, LOCK_TRY_TIMEOUT, LOCK_TRY_INTERVAL, LOCK_EXPIRE); } /** * 嘗試獲取全域性鎖 * * @param lock * 鎖的名稱 * @param timeout * 獲取超時時間 單位ms * @return true 獲取成功,false獲取失敗 */ public boolean tryLock(Lock lock, long timeout) { return getLock(lock, timeout, LOCK_TRY_INTERVAL, LOCK_EXPIRE); } /** * 嘗試獲取全域性鎖 * * @param lock * 鎖的名稱 * @param timeout * 獲取鎖的超時時間 * @param tryInterval * 多少毫秒嘗試獲取一次 * @return true 獲取成功,false獲取失敗 */ public boolean tryLock(Lock lock, long timeout, long tryInterval) { return getLock(lock, timeout, tryInterval, LOCK_EXPIRE); } /** * 嘗試獲取全域性鎖 * * @param lock * 鎖的名稱 * @param timeout * 獲取鎖的超時時間 * @param tryInterval * 多少毫秒嘗試獲取一次 * @param lockExpireTime * 鎖的過期 * @return true 獲取成功,false獲取失敗 */ public boolean tryLock(Lock lock, long timeout, long tryInterval, long lockExpireTime) { return getLock(lock, timeout, tryInterval, lockExpireTime); } /** * 操作redis獲取全域性鎖 * * @param lock * 鎖的名稱 * @param timeout * 獲取的超時時間 * @param tryInterval * 多少ms嘗試一次 * @param lockExpireTime * 獲取成功後鎖的過期時間 * @return true 獲取成功,false獲取失敗 */ public boolean getLock(Lock lock, long timeout, long tryInterval, long lockExpireTime) { try { if (StringUtils.isEmpty(lock.getName()) || StringUtils.isEmpty(lock.getValue())) { return false; } long startTime = System.currentTimeMillis(); do { if (!template.hasKey(lock.getName())) { ValueOperations<String, String> ops = template.opsForValue(); ops.set(lock.getName(), lock.getValue(), lockExpireTime, TimeUnit.MILLISECONDS); return true; } else {// 存在鎖 logger.debug("lock is exist!!!"); } if (System.currentTimeMillis() - startTime > timeout) {// 嘗試超過了設定值之後直接跳出迴圈 return false; } Thread.sleep(tryInterval); } while (template.hasKey(lock.getName())); } catch (InterruptedException e) { logger.error(e.getMessage()); return false; } return false; } /** * 釋放鎖 */ public void releaseLock(Lock lock) { if (!StringUtils.isEmpty(lock.getName())) { template.delete(lock.getName()); } } }
第四步:新增定時任務,這裡是一秒執行一次,注意@Component要加上讓系統掃描到,停用定時任務就把它拿掉!
@Component
public class MyScheduler {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private StringRedisTemplate template;
@Autowired
DistributedLockHandler distributedLockHandler;
@Scheduled(fixedRate = 1000)
public void task() throws InterruptedException {
Lock lock=new Lock("testlock","lockvalue");
if(distributedLockHandler.tryLock(lock)){
//Thread.sleep(40000);
logger.info("everOne start...");
System.out.println("template --"+template);
System.out.println("distributedLockHandler --"+distributedLockHandler);
//statusTask.healthCheck();
// int i=10/0;
logger.info("everOne end...");
distributedLockHandler.releaseLock(lock);
}
}
}
第五步:在應用程式啟動類加上註解@EnableScheduling,這個是要加上的,對計劃任務的支援
@EnableDiscoveryClient
@SpringBootApplication
@EnableScheduling
public class SpringbootApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootApplication.class, args);
}
}
ok了,你可以部署叢集了,至於怎麼部署SpringCloud注意埠號要不一樣,我這裡不多說了.