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 = 39600; private static final String LOCK_KEY_PARAMS = "nanjing_lock_key"; //分布式锁失效时间2秒 private static final int LOCK_EXPIRE_SECONDS = 2; 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 new storekey (KEY_CATEGORY, LOCK_KEY_PARAMS); // distributed lock, if you do not get the lock, directly to give up, to prevent the problem Nanjing side of the service, thereby affecting consumption MQ IF (redisStoreClient.setnx ( Lock , " Lock " , LOCK_EXPIRE_SECONDS)) { // double check, to prevent duplication get token token = redisStoreClient. gET (Key); IF (token == null ) { the try { String userId = mtConfigClient.getValue(NJ_TOKEN_USERID); LOGGER.info("mtConfigClient get userId : {}", userId); token = HttpClientUtils.post("http://" + Conf.GET_TOKEN_URL + userId, "320100", headers); LOGGER.info("get token : {} from http", token); if (StringUtils.isNotBlank(token)) { redisStoreClient.set(key, token, TOKEN_EXPIRE_SECONDS); } } The catch(HttpException The E) { LOGGER.error ( " GET errer token " , E); } } // distributed directly lock expires redisStoreClient.expire ( Lock , 0 ); } } 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 ("403".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 corresponding to the added value of Value, if added only when the Key does not exist, if Key already exists, without changing the existing value * # {@link RedisStoreClient the Add (Storekey, Object, int)} * @param key to add Key * @param value to add value * @param expireInSeconds expiration date * @return if Key does not exist and successfully added <br> returns to true * If Key already exists, returns false * @throws StoreException exceptions are StoreException subclass and is RuntimeException, can capture a corresponding exception if necessary. * As: If you need to capture a timeout exception, can capture StoreTimeoutException * / public Boolean SETNX (Storekey Key, Object value, int expireInSeconds);
The question is: Method:
getToken
use the lock method:
if (redisStoreClient.setnx (lock, "lock ", LOCK_EXPIRE_SECONDS)) {
This method does not exist and if the Key added successfully, if Key already exists, return false
to say: only key to add is successful only get token, otherwise discarded, preventing Nanjing server problems;