package com.sankuai.qcs.regulation.nanjing.util;

import com.dianping.squirrel.client.StoreKey;
import com.dianping.squirrel.client.impl.redis.RedisStoreClient;
import com.dianping.zebra.util.StringUtils;
import com.google.common.collect.Maps;
import com.sankuai.meituan.config.MtConfigClient;
import com.sankuai.qcs.regulation.nanjing.Conf;
import org.apache.http.HttpException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component; import javax.annotation.Resource;
import java.util.Map; /**
* Describe:
* Created by tanxiaolei
* Date: 2018/4/20 11:50
*/
@Component
public class TokenUtils { private static final Logger LOGGER = LoggerFactory.getLogger(TokenUtils.class); @Resource
private RedisStoreClient redisStoreClient;
@Resource
private MtConfigClient mtConfigClient; private static final String KEY_CATEGORY = "regulation_traffic";
private static final String TOKEN_KEY_PARAMS = "nanjing_token_key";
//缓存失效时间 11个小时
private static final int TOKEN_EXPIRE_SECONDS = ; private static final String LOCK_KEY_PARAMS = "nanjing_lock_key";
//分布式锁失效时间2秒
private static final int LOCK_EXPIRE_SECONDS = ; private static final String NJ_TOKEN_USERID = "NJ_TOKEN_USERID"; private static final Map<String, String> headers = Maps.newHashMap(); static {
headers.put("Connection", "keep-alive");
headers.put("Accept-Charset", Conf.DEFAULT_CHARSET);
headers.put("Content-Type", Conf.ContentType.JSON.getMimeType());
} /**
* 判断token是否在redis存在
*
* @return
*/
public boolean tokenExists() {
StoreKey key = new StoreKey(KEY_CATEGORY, TOKEN_KEY_PARAMS);
return redisStoreClient.exists(key);
} /**
* 删除指定token
*
* @return
*/
public void delToken() {
StoreKey key = new StoreKey(KEY_CATEGORY, TOKEN_KEY_PARAMS);
LOGGER.info("key : {} delete {}", key, redisStoreClient.delete(key));
} /**
* 获取token
*
* @return
*/
public String getToken() {
StoreKey key = new StoreKey(KEY_CATEGORY, TOKEN_KEY_PARAMS);
String token = redisStoreClient.get(key);
LOGGER.info("get token :{} from redis", token);
if (token == null) {
StoreKey lock = new StoreKey(KEY_CATEGORY, LOCK_KEY_PARAMS);
//分布式锁,如果没拿到锁,则直接放弃,防止南京侧服务出现问题,影响MQ消费
if (redisStoreClient.setnx(lock, "lock", LOCK_EXPIRE_SECONDS)) {
//双重检验,防止重复获取token
token = redisStoreClient.get(key);
if (token == null) {
try {
String userId = mtConfigClient.getValue(NJ_TOKEN_USERID);
LOGGER.info("mtConfigClient get userId : {}", userId);
token = HttpClientUtils.post("http://" + Conf.GET_TOKEN_URL + userId, "", headers);
LOGGER.info("get token : {} from http", token);
if (StringUtils.isNotBlank(token)) {
redisStoreClient.set(key, token, TOKEN_EXPIRE_SECONDS);
}
} catch (HttpException e) {
LOGGER.error("get token errer", e);
}
}
//将分布式锁直接过期
redisStoreClient.expire(lock, );
}
}
return token;
}
}
package com.sankuai.qcs.regulation.nanjing.util;

import com.sankuai.qcs.regulation.nanjing.Conf;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component; import javax.websocket.ClientEndpoint;
import javax.websocket.CloseReason;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session; /**
* Describe:
* Created by tanxiaolei
* Date: 2018/4/18 14:26
*/
@ClientEndpoint
@Component
public class WebSocketClientUtils { // @Autowired
// private TokenUtils tokenUtils; private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketClientUtils.class); private static ApplicationContext applicationContext; public static ApplicationContext getApplicationContext() {
return applicationContext;
} public static void setApplicationContext(ApplicationContext applicationContext) {
WebSocketClientUtils.applicationContext = applicationContext;
} @OnOpen
public void onOpen(Session session) {
//经过试验,客户端设置 buffer size时并不生效
session.setMaxBinaryMessageBufferSize(Conf.BINARY_MESSAGE_BUFFER_SIZE);
session.setMaxTextMessageBufferSize(Conf.BINARY_MESSAGE_BUFFER_SIZE);
LOGGER.info("Session {}, {} Connected", session.getId(), session.getRequestParameterMap());
} @OnMessage
public void onMessage(String message, Session session) {
LOGGER.info("Session receive message : {}", message);
//如果是403,表示token失效
if ("".equals(message)) {
delAndGetNewToken();
}
} @OnClose
public void onClose(Session session, CloseReason closeReason) {
LOGGER.info("Session max buffer size {} {} close because of {}", session.getMaxBinaryMessageBufferSize(), session.getRequestParameterMap(), closeReason);
} @OnError
public void onError(Session session, Throwable throwable) {
if (session != null) {
LOGGER.error("Session {} error", session.getRequestParameterMap(), throwable);
} else {
LOGGER.error("error", throwable);
}
} private void delAndGetNewToken() {
TokenUtils tokenUtils = (TokenUtils) applicationContext.getBean(TokenUtils.class);
LOGGER.info("toeknUtils : {}", tokenUtils);
tokenUtils.delToken();
LOGGER.info("again get token : {}", tokenUtils.getToken());
} }
    /**
* 添加 Key 对应的值为 Value,只有当 Key 不存在时才添加,如果 Key 已经存在,不改变现有的值
* {@link RedisStoreClient#add(StoreKey, Object, int)}
* @param key 要添加的 Key
* @param value 要添加的 Value
* @param expireInSeconds 过期时间
* @return 如果 Key 不存在且添加成功,返回 true<br>
* 如果 Key 已经存在,返回 false
* @throws StoreException 异常都是 StoreException 的子类且是 RuntimeException,可以根据需要捕获相应异常。
* 如:如果需要捕获超时异常,可以捕获 StoreTimeoutException
*/
public Boolean setnx(StoreKey key, Object value, int expireInSeconds);

问题的关键是:方法:

getToken
使用了加锁方法:
if (redisStoreClient.setnx(lock, "lock", LOCK_EXPIRE_SECONDS)) {
这个方法 如果 Key 不存在且添加成功, 如果 Key 已经存在,返回 false
也就是说:只有key添加成功的话才获取token,否则丢弃,防止南京服务器出问题;

分布式锁获取token的更多相关文章

  1. zookeeper分布式锁原理

    一.分布式锁介绍分布式锁主要用于在分布式环境中保护跨进程.跨主机.跨网络的共享资源实现互斥访问,以达到保证数据的一致性. 二.架构介绍在介绍使用Zookeeper实现分布式锁之前,首先看当前的系统架构 ...

  2. Redis分布式锁----悲观锁实现,以秒杀系统为例

    摘要:本文要实现的是一种使用redis来实现分布式锁. 1.分布式锁 分布式锁在是一种用来安全访问分式式机器上变量的安全方案,一般用在全局id生成,秒杀系统,全局变量共享.分布式事务等.一般会有两种实 ...

  3. ZooKeeper典型应用场景:分布式锁

    分布式锁是控制分布式系统之间同步访问共享资源的一种方式.如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要通过一些互斥手段来防止彼此之间的干扰,以保证一致 ...

  4. zookeeper【5】分布式锁

    我们常说的锁是单进程多线程锁,在多线程并发编程中,用于线程之间的数据同步,保护共享资源的访问.而分布式锁,指在分布式环境下,保护跨进程.跨主机.跨网络的共享资源,实现互斥访问,保证一致性. 架构图: ...

  5. org.apache.curator:master选举和分布式锁

    1. master选举(LeaderSelector) 1)LeaderSelector构造函数 在leaderPath上建立分布式锁:mutex = new InterProcessMutex(cl ...

  6. 求你了,别再问我Zookeeper如何实现分布式锁了!!!

    导读 真是有人(锁)的地方就有江湖(事务),今天不谈江湖,来撩撩人. 分布式锁的概念.为什么使用分布式锁,想必大家已经很清楚了.前段时间作者写过Redis是如何实现分布式锁,今天这篇文章来谈谈Zook ...

  7. 分布式锁没那么难,手把手教你实现 Redis 分布锁!|保姆级教程

    书接上文 上篇文章「MySQL 可重复读,差点就让我背上了一个 P0 事故!」发布之后,收到很多小伙伴们的留言,从中又学习到很多,总结一下. 上篇文章可能举得例子有点不恰当,导致有些小伙伴没看懂为什么 ...

  8. 图解Janusgraph系列-并发安全:锁机制(本地锁+分布式锁)分析

    图解Janusgraph系列-并发安全:锁机制(本地锁+分布式锁)分析 大家好,我是洋仔,JanusGraph图解系列文章,实时更新~ 图数据库文章总目录: 整理所有图相关文章,请移步(超链):图数据 ...

  9. redis分布式锁-spring boot aop+自定义注解实现分布式锁

    接这这一篇redis分布式锁-java实现末尾,实现aop+自定义注解 实现分布式锁 1.为什么需要 声明式的分布式锁 编程式分布式锁每次实现都要单独实现,但业务量大功能复杂时,使用编程式分布式锁无疑 ...

随机推荐

  1. hdu_1012_u Calculate e_201310121519

    u Calculate eTime Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tota ...

  2. [bzoj4010][HNOI2015]菜肴制作_贪心_拓扑排序

    菜肴制作 bzoj-4010 HNOI-2015 题目大意:给定一张n个点m条边的有向图,求一个toposort,使得:(1)满足编号为1的点尽量在前:(2)满足(1)的情况下编号为2的点尽量在前,以 ...

  3. ACdream区域赛指导赛之专题赛系列(1)の数学专场

    Contest : ACdream区域赛指导赛之专题赛系列(1)の数学专场 A:EOF女神的相反数 题意:n(<=10^18)的数转化成2进制.翻转后(去掉前导零)输出十进制 思路:water ...

  4. 读取到配置文件的C语言的接口实现

    /*********************************************************************  * Author  : Samson  * Date   ...

  5. 熊猫猪新系统測试之中的一个:Windows 10 技术预览版

    话说本猫不用windows非常多年了呀! 只是看到微软最新的Windows10还是手痒了.想安装体验一把. 于是第一时间下载,并做成usb引导安装镜像,在08年的老台式机上安装尝鲜鸟.下载ISO和安装 ...

  6. 【Android开发VR实战】三.开发一个寻宝类VR游戏TreasureHunt

    转载请注明出处:http://blog.csdn.net/linglongxin24/article/details/53939303 本文出自[DylanAndroid的博客] [Android开发 ...

  7. linux下多线程的调试

    多线程调试的基本命令(均在gdb命令行使用):    info threads ---- 显示当前可调试的全部线程.每个线程都有自己的线程ID,显示结果中前面有*的表示当前调试的线程.    eg: ...

  8. HDU - 3622 Bomb Game(二分+2-SAT)

    题目大意:玩一个放炸弹游戏,有N次放炸弹的机会,每次放炸弹时,你都有两个位置能够选择.问怎样放炸弹,能使爆炸的炸弹的半径的最小值最大(炸弹爆炸半径能够控制,可是爆炸形成的圈不能有重叠部分) 解题思路: ...

  9. Privoxy shadowscocks代理

    ubuntu已经启动好了sock5的代理, 代理为: 127.0.0.1:1080. #使用Privoxy将sock5代理映射为http代理. 安装Privoxy sudo apt-get updat ...

  10. 洛谷 P3953 [ NOIP 2017 ] 逛公园 —— 最短路DP

    题目:https://www.luogu.org/problemnew/show/P3953 主要是看题解...还是觉得好难想啊... dfs DP,剩余容量的损耗是边权减去两点最短路差值...表示对 ...