终于啊,我的朋友找到我。
场景是这样的,系统需要调用统一认证系统获取clientToken,多个微服务使用同一个clientId,生成的clientToken三十分钟有效,同一时间只有一个clientToken有效,每次调用都会产生一个新的clientToken,前一个失效。
这种场景下,要锁了吧,必须锁吧,我认为必须锁。
锁加在了生成token时。代码如下:
public GenerateTokenResp generateClientToken() throws RestClientException, ServiceCommonBusinessException {
//先从redis中取token
GenerateTokenResp clientToken = getGenerateTokenRespFromRedis();
if (!ObjectUtils.isEmpty(clientToken)){
return clientToken;
}
//没有???加锁获取存储
storeClientToken();
return getGenerateTokenRespFromRedis();
}
private GenerateTokenResp getGenerateTokenRespFromRedis(){
Object object = redisTemplate.opsForValue().get(BaseConstant.CLIENT_TOKEN_KEY);
if (null != object){
return JSONObject.parseObject(String.valueOf(object),GenerateTokenResp.class);
}
return null;
}
public void storeClientToken(){
//自旋,跟jdk学的,感觉没毛病
for (;;){
//先看有没有,万一有了呢,别旋了得停了
if (!ObjectUtils.isEmpty(getGenerateTokenRespFromRedis())){
return;
}
//获取锁,(NX键不存在 XX键存在 )(PX毫秒 EX秒) String result = redisTemplate.execute((RedisCallback<String>) connection -> {
JedisCommands commands = (JedisCommands) connection.getNativeConnection();
return commands.set(BasemConstant.CLIENT_TOKEN_LOCK_KEY, "locked", "NX", "PX", BaseConstant.CLIENT_TOKEN_LOCK_SAFE);
});
if ("OK".equals(result)){
//拿到锁了
try {
//调用接口获取token
GenerateTokenResp clientToken = getClientToken();
//成功存起来
redisTemplate.opsForValue().set(BaseConstant.CLIENT_TOKEN_KEY,JSONObject.toJSONString(clientToken),BaseConstant.CLIENT_TOKEN_SAFE, TimeUnit.MINUTES);
return;
} catch (RestClientException | ServiceCommonBusinessException e) {
//失败释放锁
redisTemplate.delete(BaseConstant.CLIENT_TOKEN_LOCK_KEY);
}
}
}}朋友啊朋友,看起来应该没有问题对不对,感觉逻辑上也说的过去。