一、背景

微信公众号调用接口的accesstoken,失效期为7200秒,所以我们需要把它缓存起来,不用每次都去获取新的。

二、方案

将accesstoken保存再redis中,设置失效时间,并在代码中检测是否有缓存值,没有则去获取并更新redis。但会出现一个问题,在多进程的模式下,会出现并发去获取accesstoken的场景,这样会导致前边的值失效,但前边的值已经缓存到redis中,后边的进程发现redis中有值,则不去更新redis,会造成之后的请求accesstoken一直失效的问题。解决方案采用的是redis的分布式锁来实现进程间并发的问题。

三、代码

package com.wuage.wechat.service.center.utils;import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationObjectSupport;import com.alibaba.fastjson.JSON;
import com.wuage.wechat.model.WechatConfig;
import com.wuage.wechat.model.WechatMessageResult;
import com.wuage.wechat.service.center.redis.MessageJedisPool;import redis.clients.jedis.Jedis;/*** 类SingleWechatAccessToken.java的实现描述:TODO 类实现描述* * @author wangpeng 2017年1月18日 下午3:39:47*/
@Component
public class WechatAccessToken extends WebApplicationObjectSupport implements InitializingBean {private Logger            logger                    = LoggerFactory.getLogger(WechatAccessToken.class);private MessageJedisPool  messageJedisPool;private volatile String   accessToken               = "";private final String      WECHAT_ACCESSTOKEN_KEY    = PropertiesUtil.getParameter("wechat.accesstoken.key");private final int         WECHAT_ACCESSTOKEN_EXPIRE = 6000;                                                  // key超时时间(秒)private static final long LOCK_TIMEOUT              = 3000;private static final long SLEEP_TIME                = 1000;private long              lock_timeout              = 0;private String            LOCK_KEY                  = PropertiesUtil.getParameter("wechat.accesstoken.lock");/*** @return the accessToken*/public String getAccessToken() {checkAndResetAccessToken();return accessToken;}/*** @Description:检查并重新获取accesstoken* @Author:wangpeng* @Date:2017年1月19日* @Return:void*/private void checkAndResetAccessToken() {Jedis jedis = messageJedisPool.getJedis();try {if (jedis != null) {String token = jedis.get(WECHAT_ACCESSTOKEN_KEY);if (StringUtils.isBlank(token)) {if (getLock().longValue() == 1) {resetAccessToken();releaseLock();}} else {accessToken = token;}}} catch (Exception e) {logger.error("get wechat access token throw exception :{}", e);} finally {if (jedis != null) {jedis.close();}}}/*** @Description:重新获取accesstoken* @Author:wangpeng* @Date:2017年1月19日* @Return:void*/public void resetAccessToken() {logger.info("get wechat access token before,token is " + accessToken);StringBuilder sb = new StringBuilder();sb.append(WechatConfig.ACCESS_TOKEN_URL);sb.append("&appid=");sb.append(PropertiesUtil.getParameter("WX_APPID"));sb.append("&secret=");sb.append(PropertiesUtil.getParameter("WX_APPSECRET"));// sb.append("546c1511fa8182c6c65db70197f2ebb6");String result = HttpClientUtil.HttpGetService(sb.toString());WechatMessageResult wmr = JSON.parseObject(result, WechatMessageResult.class);if (wmr != null) {accessToken = wmr.getAccess_token();setAccessTokenOnRedis(wmr.getAccess_token());logger.info("get wechat access token after,token is " + accessToken);}}/*** @Description:缓存accesstoken* @Author:wangpeng* @Date:2017年1月19日* @Return:void*/private void setAccessTokenOnRedis(String token) {Jedis jedis = messageJedisPool.getJedis();try {if (jedis != null) {String state = jedis.set(WECHAT_ACCESSTOKEN_KEY, token);Long expire = jedis.expire(WECHAT_ACCESSTOKEN_KEY, WECHAT_ACCESSTOKEN_EXPIRE);logger.info("set access token state is " + state);logger.info("access token expire time is " + expire);}} catch (Exception e) {logger.error("set access token on redis throw excpetion :{}", e);} finally {if (jedis != null) {jedis.close();}}}/*** @Description:获取锁* @Author:wangpeng* @Date:2017年2月10日* @Return:Long*/private Long getLock() {Long lock = 0L;Jedis jedis = messageJedisPool.getJedis();try {if (jedis != null) {while (lock != 1) {long now = System.currentTimeMillis();lock_timeout = now + LOCK_TIMEOUT + 1000;lock = jedis.setnx(LOCK_KEY, lock_timeout + "");if (lock.longValue() == 1 || (now > Long.parseLong(jedis.get(LOCK_KEY))&& now > Long.parseLong(jedis.getSet(LOCK_KEY, lock_timeout + "")))) {break;} else {Thread.sleep(SLEEP_TIME);}}}} catch (Exception e) {logger.error("getLock failed throw excpetion :{}", e);} finally {if (jedis != null) {jedis.close();}}return lock;}/*** @Description:释放锁* @Author:wangpeng* @Date:2017年2月10日* @Return:void*/private void releaseLock() {Jedis jedis = messageJedisPool.getJedis();try {if (jedis != null) {long now = System.currentTimeMillis();if (now < lock_timeout) {Long result = jedis.del(LOCK_KEY);logger.info("release lock result:" + result);}}} catch (Exception e) {logger.error("releaseLock failed throw excpetion :{}", e);} finally {if (jedis != null) {jedis.close();}}}/*** @Description:* @Author:wangpeng* @Date:2017年1月22日*/@Overridepublic void afterPropertiesSet() throws Exception {WebApplicationContext wac = getWebApplicationContext();messageJedisPool = (MessageJedisPool) wac.getBean("messageJedisPool");}}

缓存微信accesstoken实现相关推荐

  1. java获取微信accessToken

    java获取微信accessToken java获取微信accessToken GET请求 java获取微信accessToken package com.fengdi.lianmeng.task;i ...

  2. 采用java单例模式实现微信AccessToken和Jsapi_ticket缓存支持

    一.单例模式介绍 java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必 ...

  3. 基于senparc实现的微信AccessToken接口全局统一获取

    在senparc中实现了AccessToken的全局获取方式,因微信项目涉及跨语言.跨团队,外包方式的合作,需要通过接口方式供合作方调用,现将使用webapi实现的接口分享给大家: 1.自定义一个对外 ...

  4. 获取企业微信access-token

    @Resourceprivate RedisTemplate<String, Object> redisTemplate;/*** 获取access-token*/@GetMapping( ...

  5. 同时存多个变量缓存 微信小程序_微信小程序 缓存(本地缓存、异步缓存、同步缓存)详解...

    微信小程序 缓存 关于本地缓存 1.wx.setStorage(wx.setStorageSync).wx.getStorage(wx.getStorageSync).wx.clearStorage( ...

  6. php微信网页不缓存,微信浏览器取消缓存的方法

    这篇文章主要介绍了微信浏览器取消缓存的方法,本文使用meta头信息实现取消了微信浏览器的缓存,特别是在开发时会经常用到,需要的朋友可以参考下. 做微信公众号和调试手机页面的时候,避免不了页面要跳转到微 ...

  7. 小程序怎么清服务器缓存,怎么清理微信小程序缓存 微信小程序缓存删除的方法...

    微信小程序上线之后,关注的小程序越多,哪么将占用的手机空间就越大,这些程序会产生一定的缓存,那么怎么清理小程序缓存呢?微信小程序内的缓存到底如何清除?和小编一起来看看删除微信小程序缓存的方法吧. 一些 ...

  8. php微信网页不缓存,微信中浏览器缓存了不该缓存的网页?

    服务端 用的 python的flask框架 返回静态文件代码如下 flask.send_file('../static/js/main.js',cache_timeout=0) request hea ...

  9. php access token缓存,微信小程序PHP 生成access_token存入缓存

    每个小程序都会对应后台的一系列接口.access_token一天2000次,每个有效期为2小时.所以可以保存到缓存中,每隔一段时间去获取一次. 把appid和secret放在全局配置文件中,方便调用 ...

最新文章

  1. DOM0,DOM2,DOM3事件,事件基础知识入门
  2. 安装配置Kali虚拟机----linux----kali
  3. go使用之-编译约束
  4. html header文件格式类
  5. C++string容器-字符串比较
  6. AtCoder Regular Contest 120 C - Swaps 2 线段树模拟
  7. 你尝试登录的服务器语言不通,七骑士国内服务器正式上线后,各种登录问题解决方案汇总...
  8. Linux之crontab命令
  9. ajax 上传文件实例,Ajax 之文件上传
  10. java keytool 导出证书_keytool导出证书
  11. 读书笔记丨《数据产品经理修炼手册:从零基础到大数据产品实践》丨DAY4
  12. C\C++关键字---学习
  13. 输出每个数字对应的拼音
  14. 2021年中国饲料添加剂行业发展现状分析(附产值、市场供需现状、进出口贸易)[图]
  15. 8个非常重要的公式,请务必转给你身边的人
  16. 插画怎么构图?小白快速上手教程
  17. CocosCreator之微信小游戏的抽奖转盘
  18. 怎样用计算机做ppt,怎样在家用电脑上制作幻灯片?
  19. 回调函数 简单理解
  20. 【2023秋招大厂真题】携程校招-2022.9.28-k-好数组

热门文章

  1. 一个女人频繁做这些事,真的很爱你
  2. 焦虑,不知所措,努力应对,坦然,双非本硕求职算法的故事
  3. matlab拟合伽玛曲线,HDR详解 - 伽玛曲线
  4. 使用ffmpeg实现单线程异步的视频播放器
  5. 师范类大学计算机排名,这些师范类院校排名全国前五!有你喜欢的吗?
  6. 研究生的压力应对与心理健康期末考试答案
  7. 16日,7月,2012 - 昨天晚睡 | 整理电脑 | 没有进度
  8. ECshop文件结构说明
  9. Ionic + Vue3 + Capacitor 配置环境、打包应用常见问题
  10. ZABBIX 监控基本报警故障