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. Intellij Idea:创建带签名的APK

    步骤如下: 1. 选择菜单Build -> Generate Signed APK… 2. 创建或选择已存在的Key Store(选择已存在的Key Store的话直接跳到第5步) 3. 输入K ...

  2. SUSE Linux Enterprise Serve 12 试用体验

    SUSE Linux Enterprise Serve 12 试用体验 大家都知道德国出产的奔驰.宝马.等车型以精美.可靠.耐用而著称.而相同出自德国人之手的Suse Linux .即使是被收购也是一 ...

  3. 一篇文章贯穿ACE各种发送接收组件 1.2版

    TCP通信过程介绍 首先介绍一下socket通信的基本过程:这里先如果有两个家伙在通信,一个是S.还有一个叫C (1)S打开port监听本地的port看看有没有人来连接: (2)与此同一时候C试图去连 ...

  4. ActionBar第一课简单介绍

    .ActionBar简单介绍 ActionBar是显示在界面顶部的标题栏. 官方推荐开发者尽量使用 ActionBar代替OptionsMenu和TabHost. 典型应用方式有: 使用导航栏中的应用 ...

  5. 阻尼滑动--能够滑动过度的ScrollView(OverScrollView)

    贴上一个我自己用过的阻尼滑动的ScrollView,像QQ里面那种滑动效果,尽管不是我写的,可是我认为还能够,贴出来做个记录,实用到的时候免得到处去找. 代码例如以下: /* * Copyright ...

  6. UI设计---&gt;全心全意为人民服务的宗旨----&gt;注重客户体验---&gt;软件持久的生命力

    UI即User Interface(用户界面)的简称. UI设计是指对软件的人机交互.操作逻辑.界面美观的总体设计. 好的UI设计不仅是让软件变得有个性有品味,还要让软件的操作变得舒适简单.自由.充分 ...

  7. 【bzoj2038】[2009国家集训队]小Z的袜子(hose)(细致总结)

    [bzoj2038][2009国家集训队]小Z的袜子(hose)(细致总结) Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z ...

  8. RTP协议分析和详解

    一.RTP协议分析 第1章.     RTP概述 1.1.  RTP是什么 RTP全名是Real-time Transport Protocol(实时传输协议).它是IETF提出的一个标准,对应的RF ...

  9. bzoj1895

    fhqtreap 其实fhqtreap只有可持久化之后才用新建节点... reverse和splay一样. //#include<bits/stdc++.h> #include<cs ...

  10. 0604-面向对象、类与对象、类、static、构造方法/析构方法

    一.面向对象 1.面向过程:一个人分步骤完成某个事情 2.面向对象:某件事情拆分为多个任务,由每个对象独立完成,最后调用整合为一个完整的项目 3.三要素:继承.封装.多态. 封装:私有化属性 提供公共 ...