| @@ -0,0 +1,280 @@ | |||
| package cn.binarywang.wx.miniapp.config.impl; | |||
| import com.github.jedis.lock.JedisLock; | |||
| import redis.clients.jedis.Jedis; | |||
| import java.io.File; | |||
| import java.util.HashMap; | |||
| import java.util.Map; | |||
| import java.util.concurrent.TimeUnit; | |||
| import java.util.concurrent.locks.Condition; | |||
| import java.util.concurrent.locks.Lock; | |||
| /** | |||
| * @author <a href="https://github.com/winter4666">winter</a> | |||
| */ | |||
| public abstract class AbstractWxMaRedisConfig extends WxMaDefaultConfigImpl { | |||
| public interface JedisConfig { | |||
| Jedis config(Jedis jedis); | |||
| } | |||
| private static final String ACCESS_TOKEN = "accessToken"; | |||
| private static final String JSAPI_TICKET = "jsapiTicket"; | |||
| private static final String CARD_API_TICKET = "cardApiTicket"; | |||
| private static final String HASH_VALUE_FIELD = "value"; | |||
| private static final String HASH_EXPIRE_FIELD = "expire"; | |||
| /** | |||
| * Redis Key 的前缀,默认为 maConfig | |||
| */ | |||
| private String redisKeyPrefix = "maConfig"; | |||
| /** | |||
| * 微信小程序唯一id,用于拼接存储到redis时的key,防止key重复. | |||
| */ | |||
| private String maId; | |||
| private Lock accessTokenLock; | |||
| private Lock jsapiTicketLock; | |||
| private Lock cardApiTicketLock; | |||
| /** | |||
| * 临时文件目录. | |||
| */ | |||
| protected volatile File tmpDirFile; | |||
| /** | |||
| * 对从 JedisPool.getResource() 获取到的每个 Jedis 实例进行配置 | |||
| */ | |||
| private JedisConfig jedisConfig; | |||
| protected abstract Jedis getJedis(); | |||
| private Jedis getConfiguredJedis() { | |||
| Jedis jedis = getJedis(); | |||
| if (jedisConfig != null) { | |||
| return jedisConfig.config(jedis); | |||
| } else { | |||
| return jedis; | |||
| } | |||
| } | |||
| private String getRedisKey(String key) { | |||
| StringBuilder redisKey = new StringBuilder(redisKeyPrefix).append(":"); | |||
| if (maId == null) { | |||
| return redisKey.append(key).toString(); | |||
| } else { | |||
| return redisKey.append(maId).append(":").append(key).toString(); | |||
| } | |||
| } | |||
| private String getValueFromRedis(String key) { | |||
| try (Jedis jedis = getConfiguredJedis()) { | |||
| return jedis.hget(getRedisKey(key), HASH_VALUE_FIELD); | |||
| } | |||
| } | |||
| private void setValueToRedis(String key, long expiresTime, String value) { | |||
| try (Jedis jedis = getConfiguredJedis()) { | |||
| Map<String, String> hash = new HashMap<String, String>(); | |||
| hash.put(HASH_VALUE_FIELD, value); | |||
| hash.put(HASH_EXPIRE_FIELD, String.valueOf(expiresTime)); | |||
| jedis.hmset(getRedisKey(key), hash); | |||
| } | |||
| } | |||
| private long getExpireFromRedis(String key) { | |||
| try (Jedis jedis = getConfiguredJedis()) { | |||
| String expire = jedis.hget(getRedisKey(key), HASH_EXPIRE_FIELD); | |||
| return expire == null ? 0 : Long.parseLong(expire); | |||
| } | |||
| } | |||
| private void setExpire(String key, long expiresTime) { | |||
| try (Jedis jedis = getConfiguredJedis()) { | |||
| jedis.hset(getRedisKey(key), HASH_EXPIRE_FIELD, String.valueOf(expiresTime)); | |||
| } | |||
| } | |||
| public void setRedisKeyPrefix(String redisKeyPrefix) { | |||
| this.redisKeyPrefix = redisKeyPrefix; | |||
| } | |||
| public void setJedisConfig(JedisConfig jedisConfig) { | |||
| this.jedisConfig = jedisConfig; | |||
| } | |||
| public void setMaId(String maId) { | |||
| this.maId = maId; | |||
| } | |||
| @Override | |||
| public String getAccessToken() { | |||
| return getValueFromRedis(ACCESS_TOKEN); | |||
| } | |||
| @Override | |||
| public Lock getAccessTokenLock() { | |||
| if (accessTokenLock == null) { | |||
| synchronized (this) { | |||
| if (accessTokenLock == null) { | |||
| accessTokenLock = new DistributedLock(getRedisKey("accessTokenLock")); | |||
| } | |||
| } | |||
| } | |||
| return accessTokenLock; | |||
| } | |||
| @Override | |||
| public boolean isAccessTokenExpired() { | |||
| return isExpired(getExpireFromRedis(ACCESS_TOKEN)); | |||
| } | |||
| @Override | |||
| public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) { | |||
| setValueToRedis(ACCESS_TOKEN, expiresAheadInMillis(expiresInSeconds), accessToken); | |||
| } | |||
| @Override | |||
| public String getJsapiTicket() { | |||
| return getValueFromRedis(JSAPI_TICKET); | |||
| } | |||
| @Override | |||
| public Lock getJsapiTicketLock() { | |||
| if (jsapiTicketLock == null) { | |||
| synchronized (this) { | |||
| if (jsapiTicketLock == null) { | |||
| jsapiTicketLock = new DistributedLock(getRedisKey("jsapiTicketLock")); | |||
| } | |||
| } | |||
| } | |||
| return jsapiTicketLock; | |||
| } | |||
| @Override | |||
| public boolean isJsapiTicketExpired() { | |||
| return isExpired(getExpireFromRedis(JSAPI_TICKET)); | |||
| } | |||
| @Override | |||
| public void expireJsapiTicket() { | |||
| setExpire(JSAPI_TICKET, 0); | |||
| } | |||
| @Override | |||
| public void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) { | |||
| setValueToRedis(JSAPI_TICKET, expiresAheadInMillis(expiresInSeconds), jsapiTicket); | |||
| } | |||
| @Override | |||
| public String getCardApiTicket() { | |||
| return getValueFromRedis(CARD_API_TICKET); | |||
| } | |||
| @Override | |||
| public Lock getCardApiTicketLock() { | |||
| if (cardApiTicketLock == null) { | |||
| synchronized (this) { | |||
| if (cardApiTicketLock == null) { | |||
| cardApiTicketLock = new DistributedLock(getRedisKey("cardApiTicketLock")); | |||
| } | |||
| } | |||
| } | |||
| return cardApiTicketLock; | |||
| } | |||
| @Override | |||
| public boolean isCardApiTicketExpired() { | |||
| return isExpired(getExpireFromRedis(CARD_API_TICKET)); | |||
| } | |||
| @Override | |||
| public void expireCardApiTicket() { | |||
| setExpire(CARD_API_TICKET, 0); | |||
| } | |||
| @Override | |||
| public void updateCardApiTicket(String cardApiTicket, int expiresInSeconds) { | |||
| setValueToRedis(CARD_API_TICKET, expiresAheadInMillis(expiresInSeconds), cardApiTicket); | |||
| } | |||
| @Override | |||
| public void expireAccessToken() { | |||
| setExpiresTime(0); | |||
| } | |||
| @Override | |||
| public long getExpiresTime() { | |||
| return getExpireFromRedis(ACCESS_TOKEN); | |||
| } | |||
| @Override | |||
| public void setExpiresTime(long expiresTime) { | |||
| setExpire(ACCESS_TOKEN, expiresTime); | |||
| } | |||
| /** | |||
| * 基于redis的简单分布式锁. | |||
| */ | |||
| private class DistributedLock implements Lock { | |||
| private JedisLock lock; | |||
| private DistributedLock(String key) { | |||
| this.lock = new JedisLock(getRedisKey(key)); | |||
| } | |||
| @Override | |||
| public void lock() { | |||
| try (Jedis jedis = getConfiguredJedis()) { | |||
| if (!lock.acquire(jedis)) { | |||
| throw new RuntimeException("acquire timeouted"); | |||
| } | |||
| } catch (InterruptedException e) { | |||
| throw new RuntimeException("lock failed", e); | |||
| } | |||
| } | |||
| @Override | |||
| public void lockInterruptibly() throws InterruptedException { | |||
| try (Jedis jedis = getConfiguredJedis()) { | |||
| if (!lock.acquire(jedis)) { | |||
| throw new RuntimeException("acquire timeouted"); | |||
| } | |||
| } | |||
| } | |||
| @Override | |||
| public boolean tryLock() { | |||
| try (Jedis jedis = getConfiguredJedis()) { | |||
| return lock.acquire(jedis); | |||
| } catch (InterruptedException e) { | |||
| throw new RuntimeException("lock failed", e); | |||
| } | |||
| } | |||
| @Override | |||
| public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { | |||
| try (Jedis jedis = getConfiguredJedis()) { | |||
| return lock.acquire(jedis); | |||
| } | |||
| } | |||
| @Override | |||
| public void unlock() { | |||
| try (Jedis jedis = getConfiguredJedis()) { | |||
| lock.release(jedis); | |||
| } | |||
| } | |||
| @Override | |||
| public Condition newCondition() { | |||
| throw new RuntimeException("unsupported method"); | |||
| } | |||
| } | |||
| } | |||
| @@ -48,6 +48,20 @@ public class WxMaDefaultConfigImpl implements WxMaConfig { | |||
| private volatile ApacheHttpClientBuilder apacheHttpClientBuilder; | |||
| /** | |||
| * 会过期的数据提前过期时间,默认预留200秒的时间 | |||
| */ | |||
| protected long expiresAheadInMillis(int expiresInSeconds) { | |||
| return System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; | |||
| } | |||
| /** | |||
| * 判断 expiresTime 是否已经过期 | |||
| */ | |||
| protected boolean isExpired(long expiresTime) { | |||
| return System.currentTimeMillis() > expiresTime; | |||
| } | |||
| @Override | |||
| public String getAccessToken() { | |||
| return this.accessToken; | |||
| @@ -68,7 +82,7 @@ public class WxMaDefaultConfigImpl implements WxMaConfig { | |||
| @Override | |||
| public boolean isAccessTokenExpired() { | |||
| return System.currentTimeMillis() > this.expiresTime; | |||
| return isExpired(this.expiresTime); | |||
| } | |||
| @Override | |||
| @@ -78,8 +92,8 @@ public class WxMaDefaultConfigImpl implements WxMaConfig { | |||
| @Override | |||
| public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) { | |||
| this.accessToken = accessToken; | |||
| this.expiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; | |||
| setAccessToken(accessToken); | |||
| setExpiresTime(expiresAheadInMillis(expiresInSeconds)); | |||
| } | |||
| @Override | |||
| @@ -94,7 +108,7 @@ public class WxMaDefaultConfigImpl implements WxMaConfig { | |||
| @Override | |||
| public boolean isJsapiTicketExpired() { | |||
| return System.currentTimeMillis() > this.jsapiTicketExpiresTime; | |||
| return isExpired(this.jsapiTicketExpiresTime); | |||
| } | |||
| @Override | |||
| @@ -105,8 +119,7 @@ public class WxMaDefaultConfigImpl implements WxMaConfig { | |||
| @Override | |||
| public void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) { | |||
| this.jsapiTicket = jsapiTicket; | |||
| // 预留200秒的时间 | |||
| this.jsapiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; | |||
| this.jsapiTicketExpiresTime = expiresAheadInMillis(expiresInSeconds); | |||
| } | |||
| @@ -122,7 +135,7 @@ public class WxMaDefaultConfigImpl implements WxMaConfig { | |||
| @Override | |||
| public boolean isCardApiTicketExpired() { | |||
| return System.currentTimeMillis() > this.cardApiTicketExpiresTime; | |||
| return isExpired(this.cardApiTicketExpiresTime); | |||
| } | |||
| @Override | |||
| @@ -133,8 +146,7 @@ public class WxMaDefaultConfigImpl implements WxMaConfig { | |||
| @Override | |||
| public void updateCardApiTicket(String cardApiTicket, int expiresInSeconds) { | |||
| this.cardApiTicket = cardApiTicket; | |||
| // 预留200秒的时间 | |||
| this.cardApiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; | |||
| this.cardApiTicketExpiresTime = expiresAheadInMillis(expiresInSeconds); | |||
| } | |||
| @Override | |||
| @@ -1,377 +1,40 @@ | |||
| package cn.binarywang.wx.miniapp.config.impl; | |||
| import java.io.File; | |||
| import java.util.HashMap; | |||
| import java.util.Map; | |||
| import java.util.concurrent.TimeUnit; | |||
| import java.util.concurrent.locks.Condition; | |||
| import java.util.concurrent.locks.Lock; | |||
| import cn.binarywang.wx.miniapp.config.WxMaConfig; | |||
| import com.github.jedis.lock.JedisLock; | |||
| import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; | |||
| import me.chanjar.weixin.common.bean.WxAccessToken; | |||
| import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; | |||
| import redis.clients.jedis.Jedis; | |||
| import redis.clients.jedis.JedisPool; | |||
| /** | |||
| * 基于Redis的微信配置provider. | |||
| * 基于Redis的微信配置provider. 使用连接池 JedisPool 进行 Redis 操作。 | |||
| * | |||
| * <pre> | |||
| * 需要引入依赖<a href="https://github.com/abelaska/jedis-lock">jedis-lock</a>,才能使用该类。 | |||
| * </pre> | |||
| * | |||
| * @author <a href="https://github.com/winter4666">winter</a> | |||
| */ | |||
| public class WxMaRedisConfigImpl implements WxMaConfig { | |||
| private static final String ACCESS_TOKEN = "accessToken"; | |||
| private static final String JSAPI_TICKET = "jsapiTicket"; | |||
| private static final String CARD_API_TICKET = "cardApiTicket"; | |||
| private static final String HASH_VALUE_FIELD = "value"; | |||
| private static final String HASH_EXPIRE_FIELD = "expire"; | |||
| public class WxMaRedisConfigImpl extends AbstractWxMaRedisConfig { | |||
| private JedisPool jedisPool; | |||
| /** | |||
| * 微信小程序唯一id,用于拼接存储到redis时的key,防止key重复. | |||
| */ | |||
| private String maId; | |||
| private volatile String msgDataFormat; | |||
| protected volatile String appid; | |||
| private volatile String secret; | |||
| protected volatile String token; | |||
| private volatile String aesKey; | |||
| private volatile String httpProxyHost; | |||
| private volatile int httpProxyPort; | |||
| private volatile String httpProxyUsername; | |||
| private volatile String httpProxyPassword; | |||
| private Lock accessTokenLock; | |||
| private Lock jsapiTicketLock; | |||
| private Lock cardApiTicketLock; | |||
| /** | |||
| * 临时文件目录. | |||
| * JedisPool 在此配置类是必须项,使用 WxMaRedisConfigImpl(JedisPool) 构造方法来构造实例 | |||
| */ | |||
| protected volatile File tmpDirFile; | |||
| private volatile ApacheHttpClientBuilder apacheHttpClientBuilder; | |||
| private String getRedisKey(String key) { | |||
| StringBuilder redisKey = new StringBuilder("maConfig:"); | |||
| if (maId == null) { | |||
| return redisKey.append(key).toString(); | |||
| } else { | |||
| return redisKey.append(maId).append(":").append(key).toString(); | |||
| } | |||
| @Deprecated | |||
| public WxMaRedisConfigImpl() { | |||
| } | |||
| private String getValueFromRedis(String key) { | |||
| try (Jedis jedis = jedisPool.getResource()) { | |||
| return jedis.hget(getRedisKey(key), HASH_VALUE_FIELD); | |||
| } | |||
| } | |||
| private void setValueToRedis(String key, long expiresTime, String value) { | |||
| try (Jedis jedis = jedisPool.getResource()) { | |||
| Map<String, String> hash = new HashMap<String, String>(); | |||
| hash.put(HASH_VALUE_FIELD, value); | |||
| hash.put(HASH_EXPIRE_FIELD, String.valueOf(expiresTime)); | |||
| jedis.hmset(getRedisKey(key), hash); | |||
| } | |||
| } | |||
| private long getExpireFromRedis(String key) { | |||
| try (Jedis jedis = jedisPool.getResource()) { | |||
| String expire = jedis.hget(getRedisKey(key), HASH_EXPIRE_FIELD); | |||
| return expire == null ? 0 : Long.parseLong(expire); | |||
| } | |||
| } | |||
| private void setExpire(String key, long expiresTime) { | |||
| try (Jedis jedis = jedisPool.getResource()) { | |||
| jedis.hset(getRedisKey(key), HASH_EXPIRE_FIELD, String.valueOf(expiresTime)); | |||
| } | |||
| public WxMaRedisConfigImpl(JedisPool jedisPool) { | |||
| this.jedisPool = jedisPool; | |||
| } | |||
| /** | |||
| * 使用 WxMaRedisConfigImpl(JedisPool) 构造方法来设置 JedisPool | |||
| */ | |||
| @Deprecated | |||
| public void setJedisPool(JedisPool jedisPool) { | |||
| this.jedisPool = jedisPool; | |||
| } | |||
| public void setMaId(String maId) { | |||
| this.maId = maId; | |||
| } | |||
| @Override | |||
| public String getAccessToken() { | |||
| return getValueFromRedis(ACCESS_TOKEN); | |||
| } | |||
| @Override | |||
| public Lock getAccessTokenLock() { | |||
| if (accessTokenLock == null) { | |||
| synchronized (this) { | |||
| if (accessTokenLock == null) { | |||
| accessTokenLock = new DistributedLock(getRedisKey("accessTokenLock")); | |||
| } | |||
| } | |||
| } | |||
| return accessTokenLock; | |||
| } | |||
| @Override | |||
| public boolean isAccessTokenExpired() { | |||
| return System.currentTimeMillis() > getExpireFromRedis(ACCESS_TOKEN); | |||
| } | |||
| @Override | |||
| public synchronized void updateAccessToken(WxAccessToken accessToken) { | |||
| updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); | |||
| } | |||
| @Override | |||
| public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) { | |||
| setValueToRedis(ACCESS_TOKEN, System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L, accessToken); | |||
| } | |||
| @Override | |||
| public String getJsapiTicket() { | |||
| return getValueFromRedis(JSAPI_TICKET); | |||
| } | |||
| @Override | |||
| public Lock getJsapiTicketLock() { | |||
| if (jsapiTicketLock == null) { | |||
| synchronized (this) { | |||
| if (jsapiTicketLock == null) { | |||
| jsapiTicketLock = new DistributedLock(getRedisKey("jsapiTicketLock")); | |||
| } | |||
| } | |||
| } | |||
| return jsapiTicketLock; | |||
| } | |||
| @Override | |||
| public boolean isJsapiTicketExpired() { | |||
| return System.currentTimeMillis() > getExpireFromRedis(JSAPI_TICKET); | |||
| } | |||
| @Override | |||
| public void expireJsapiTicket() { | |||
| setExpire(JSAPI_TICKET, 0); | |||
| } | |||
| @Override | |||
| public void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) { | |||
| // 预留200秒的时间 | |||
| setValueToRedis(JSAPI_TICKET, System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L, jsapiTicket); | |||
| } | |||
| @Override | |||
| public String getCardApiTicket() { | |||
| return getValueFromRedis(CARD_API_TICKET); | |||
| } | |||
| @Override | |||
| public Lock getCardApiTicketLock() { | |||
| if (cardApiTicketLock == null) { | |||
| synchronized (this) { | |||
| if (cardApiTicketLock == null) { | |||
| cardApiTicketLock = new DistributedLock(getRedisKey("cardApiTicketLock")); | |||
| } | |||
| } | |||
| } | |||
| return cardApiTicketLock; | |||
| } | |||
| @Override | |||
| public boolean isCardApiTicketExpired() { | |||
| return System.currentTimeMillis() > getExpireFromRedis(CARD_API_TICKET); | |||
| } | |||
| @Override | |||
| public void expireCardApiTicket() { | |||
| setExpire(CARD_API_TICKET, 0); | |||
| } | |||
| @Override | |||
| public void updateCardApiTicket(String cardApiTicket, int expiresInSeconds) { | |||
| setValueToRedis(CARD_API_TICKET, System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L, cardApiTicket); | |||
| } | |||
| @Override | |||
| public void expireAccessToken() { | |||
| setExpire(ACCESS_TOKEN, 0); | |||
| } | |||
| @Override | |||
| public String getSecret() { | |||
| return this.secret; | |||
| } | |||
| public void setSecret(String secret) { | |||
| this.secret = secret; | |||
| } | |||
| @Override | |||
| public String getToken() { | |||
| return this.token; | |||
| } | |||
| public void setToken(String token) { | |||
| this.token = token; | |||
| } | |||
| @Override | |||
| public long getExpiresTime() { | |||
| return getExpireFromRedis(ACCESS_TOKEN); | |||
| } | |||
| @Override | |||
| public String getAesKey() { | |||
| return this.aesKey; | |||
| } | |||
| public void setAesKey(String aesKey) { | |||
| this.aesKey = aesKey; | |||
| } | |||
| @Override | |||
| public String getMsgDataFormat() { | |||
| return this.msgDataFormat; | |||
| } | |||
| public void setMsgDataFormat(String msgDataFormat) { | |||
| this.msgDataFormat = msgDataFormat; | |||
| } | |||
| @Override | |||
| public String getHttpProxyHost() { | |||
| return this.httpProxyHost; | |||
| } | |||
| public void setHttpProxyHost(String httpProxyHost) { | |||
| this.httpProxyHost = httpProxyHost; | |||
| } | |||
| @Override | |||
| public int getHttpProxyPort() { | |||
| return this.httpProxyPort; | |||
| } | |||
| public void setHttpProxyPort(int httpProxyPort) { | |||
| this.httpProxyPort = httpProxyPort; | |||
| } | |||
| @Override | |||
| public String getHttpProxyUsername() { | |||
| return this.httpProxyUsername; | |||
| } | |||
| public void setHttpProxyUsername(String httpProxyUsername) { | |||
| this.httpProxyUsername = httpProxyUsername; | |||
| } | |||
| @Override | |||
| public String getHttpProxyPassword() { | |||
| return this.httpProxyPassword; | |||
| } | |||
| public void setHttpProxyPassword(String httpProxyPassword) { | |||
| this.httpProxyPassword = httpProxyPassword; | |||
| } | |||
| @Override | |||
| public String toString() { | |||
| return WxMaGsonBuilder.create().toJson(this); | |||
| } | |||
| @Override | |||
| public ApacheHttpClientBuilder getApacheHttpClientBuilder() { | |||
| return this.apacheHttpClientBuilder; | |||
| } | |||
| public void setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientBuilder) { | |||
| this.apacheHttpClientBuilder = apacheHttpClientBuilder; | |||
| } | |||
| @Override | |||
| public boolean autoRefreshToken() { | |||
| return true; | |||
| } | |||
| @Override | |||
| public String getAppid() { | |||
| return appid; | |||
| } | |||
| public void setAppid(String appid) { | |||
| this.appid = appid; | |||
| } | |||
| /** | |||
| * 基于redis的简单分布式锁. | |||
| */ | |||
| private class DistributedLock implements Lock { | |||
| private JedisLock lock; | |||
| private DistributedLock(String key) { | |||
| this.lock = new JedisLock(getRedisKey(key)); | |||
| } | |||
| @Override | |||
| public void lock() { | |||
| try (Jedis jedis = jedisPool.getResource()) { | |||
| if (!lock.acquire(jedis)) { | |||
| throw new RuntimeException("acquire timeouted"); | |||
| } | |||
| } catch (InterruptedException e) { | |||
| throw new RuntimeException("lock failed", e); | |||
| } | |||
| } | |||
| @Override | |||
| public void lockInterruptibly() throws InterruptedException { | |||
| try (Jedis jedis = jedisPool.getResource()) { | |||
| if (!lock.acquire(jedis)) { | |||
| throw new RuntimeException("acquire timeouted"); | |||
| } | |||
| } | |||
| } | |||
| @Override | |||
| public boolean tryLock() { | |||
| try (Jedis jedis = jedisPool.getResource()) { | |||
| return lock.acquire(jedis); | |||
| } catch (InterruptedException e) { | |||
| throw new RuntimeException("lock failed", e); | |||
| } | |||
| } | |||
| @Override | |||
| public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { | |||
| try (Jedis jedis = jedisPool.getResource()) { | |||
| return lock.acquire(jedis); | |||
| } | |||
| } | |||
| @Override | |||
| public void unlock() { | |||
| try (Jedis jedis = jedisPool.getResource()) { | |||
| lock.release(jedis); | |||
| } | |||
| } | |||
| @Override | |||
| public Condition newCondition() { | |||
| throw new RuntimeException("unsupported method"); | |||
| } | |||
| protected Jedis getJedis() { | |||
| return jedisPool.getResource(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,24 @@ | |||
| package cn.binarywang.wx.miniapp.config.impl; | |||
| import redis.clients.jedis.Jedis; | |||
| /** | |||
| * 基于Redis的微信配置provider. 使用自己管理的 Jedis 实例进行 Redis 操作。 | |||
| * | |||
| * <pre> | |||
| * 需要引入依赖<a href="https://github.com/abelaska/jedis-lock">jedis-lock</a>,才能使用该类。 | |||
| * </pre> | |||
| */ | |||
| public class WxMaRedisConnectionConfigImpl extends AbstractWxMaRedisConfig { | |||
| public WxMaRedisConnectionConfigImpl(Jedis jedis) { | |||
| this.jedis = jedis; | |||
| } | |||
| private Jedis jedis; | |||
| @Override | |||
| protected Jedis getJedis() { | |||
| return jedis; | |||
| } | |||
| } | |||