Skip to content

Commit 04f7d76

Browse files
authored
🎨 #1487 开放平台模块三方平台获取token方法支持redis分布式锁
* 三方平台支持redis分布式锁;getComponentAccessToken 加锁 * getAuthorizerAccessToken 加锁
1 parent d703f2d commit 04f7d76

File tree

8 files changed

+160
-13
lines changed

8 files changed

+160
-13
lines changed

pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,12 @@
243243
<version>2.9.0</version>
244244
<scope>provided</scope>
245245
</dependency>
246+
<dependency>
247+
<groupId>com.github.jedis-lock</groupId>
248+
<artifactId>jedis-lock</artifactId>
249+
<version>1.0.0</version>
250+
<scope>provided</scope>
251+
</dependency>
246252
<dependency>
247253
<groupId>org.redisson</groupId>
248254
<artifactId>redisson</artifactId>

weixin-java-common/pom.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,15 @@
118118
<artifactId>dom4j</artifactId>
119119
<version>2.1.1</version>
120120
</dependency>
121+
<dependency>
122+
<groupId>redis.clients</groupId>
123+
<artifactId>jedis</artifactId>
124+
</dependency>
125+
126+
<dependency>
127+
<groupId>com.github.jedis-lock</groupId>
128+
<artifactId>jedis-lock</artifactId>
129+
</dependency>
121130
</dependencies>
122131

123132
<build>
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package me.chanjar.weixin.common.util.locks;
2+
3+
import java.util.concurrent.TimeUnit;
4+
import java.util.concurrent.locks.Condition;
5+
import java.util.concurrent.locks.Lock;
6+
import redis.clients.jedis.Jedis;
7+
import redis.clients.util.Pool;
8+
9+
/**
10+
* JedisPool 分布式锁
11+
*
12+
* @author <a href="https://github.com/007gzs">007</a>
13+
*/
14+
public class JedisDistributedLock implements Lock {
15+
private final Pool<Jedis> jedisPool;
16+
private final JedisLock lock;
17+
18+
public JedisDistributedLock(Pool<Jedis> jedisPool, String key){
19+
this.jedisPool = jedisPool;
20+
this.lock = new JedisLock(key);
21+
}
22+
23+
@Override
24+
public void lock() {
25+
try (Jedis jedis = jedisPool.getResource()) {
26+
if (!lock.acquire(jedis)) {
27+
throw new RuntimeException("acquire timeouted");
28+
}
29+
} catch (InterruptedException e) {
30+
throw new RuntimeException("lock failed", e);
31+
}
32+
}
33+
34+
@Override
35+
public void lockInterruptibly() throws InterruptedException {
36+
try (Jedis jedis = jedisPool.getResource()) {
37+
if (!lock.acquire(jedis)) {
38+
throw new RuntimeException("acquire timeouted");
39+
}
40+
}
41+
}
42+
43+
@Override
44+
public boolean tryLock() {
45+
try (Jedis jedis = jedisPool.getResource()) {
46+
return lock.acquire(jedis);
47+
} catch (InterruptedException e) {
48+
throw new RuntimeException("lock failed", e);
49+
}
50+
}
51+
52+
@Override
53+
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
54+
try (Jedis jedis = jedisPool.getResource()) {
55+
return lock.acquire(jedis);
56+
}
57+
}
58+
59+
@Override
60+
public void unlock() {
61+
try (Jedis jedis = jedisPool.getResource()) {
62+
lock.release(jedis);
63+
}
64+
}
65+
66+
@Override
67+
public Condition newCondition() {
68+
throw new RuntimeException("unsupported method");
69+
}
70+
71+
}

weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenConfigStorage.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import me.chanjar.weixin.open.bean.WxOpenAuthorizerAccessToken;
77
import me.chanjar.weixin.open.bean.WxOpenComponentAccessToken;
88

9+
import java.util.concurrent.locks.Lock;
10+
911
/**
1012
* @author <a href="https://github.com/007gzs">007</a>
1113
*/
@@ -53,6 +55,10 @@ public interface WxOpenConfigStorage {
5355

5456
WxMaConfig getWxMaConfig(String appId);
5557

58+
Lock getComponentAccessTokenLock();
59+
60+
Lock getLockByKey(String key);
61+
5662
/**
5763
* 应该是线程安全的
5864
*

weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/AbstractWxOpenInRedisConfigStorage.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ public abstract class AbstractWxOpenInRedisConfigStorage extends WxOpenInMemoryC
1313

1414
protected final static String AUTHORIZER_REFRESH_TOKEN_KEY = "wechat_authorizer_refresh_token:";
1515
protected final static String AUTHORIZER_ACCESS_TOKEN_KEY = "wechat_authorizer_access_token:";
16+
17+
protected final static String LOCK_KEY = "wechat_lock:";
18+
1619
protected final static String JSAPI_TICKET_KEY = "wechat_jsapi_ticket:";
1720
protected final static String CARD_API_TICKET_KEY = "wechat_card_api_ticket:";
1821

@@ -26,6 +29,7 @@ public abstract class AbstractWxOpenInRedisConfigStorage extends WxOpenInMemoryC
2629
protected String authorizerAccessTokenKey;
2730
protected String jsapiTicketKey;
2831
protected String cardApiTicket;
32+
protected String lockKey;
2933

3034
@Override
3135
public void setComponentAppId(String componentAppId) {
@@ -36,8 +40,9 @@ public void setComponentAppId(String componentAppId) {
3640
componentAccessTokenKey = prefix + COMPONENT_ACCESS_TOKEN_KEY.concat(componentAppId);
3741
authorizerRefreshTokenKey = prefix + AUTHORIZER_REFRESH_TOKEN_KEY.concat(componentAppId);
3842
authorizerAccessTokenKey = prefix + AUTHORIZER_ACCESS_TOKEN_KEY.concat(componentAppId);
39-
this.jsapiTicketKey = JSAPI_TICKET_KEY.concat(componentAppId);
40-
this.cardApiTicket = CARD_API_TICKET_KEY.concat(componentAppId);
43+
lockKey = prefix + LOCK_KEY.concat(componentAppId);
44+
jsapiTicketKey = prefix + JSAPI_TICKET_KEY.concat(componentAppId);
45+
cardApiTicket = prefix + CARD_API_TICKET_KEY.concat(componentAppId);
4146
}
4247

4348
protected String getKey(String prefix, String appId) {

weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenComponentServiceImpl.java

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
import java.util.List;
2525
import java.util.Map;
26+
import java.util.concurrent.locks.Lock;
2627
import java.util.concurrent.ConcurrentHashMap;
2728

2829
/**
@@ -109,18 +110,28 @@ public boolean checkSignature(String timestamp, String nonce, String signature)
109110

110111
@Override
111112
public String getComponentAccessToken(boolean forceRefresh) throws WxErrorException {
112-
113-
if (this.getWxOpenConfigStorage().isComponentAccessTokenExpired() || forceRefresh) {
113+
final WxOpenConfigStorage config = this.getWxOpenConfigStorage();
114+
if (!config.isComponentAccessTokenExpired() && !forceRefresh) {
115+
return config.getComponentAccessToken();
116+
}
117+
Lock lock = config.getComponentAccessTokenLock();
118+
lock.lock();
119+
try {
120+
if (!config.isComponentAccessTokenExpired() && !forceRefresh) {
121+
return config.getComponentAccessToken();
122+
}
114123
JsonObject jsonObject = new JsonObject();
115124
jsonObject.addProperty("component_appid", getWxOpenConfigStorage().getComponentAppId());
116125
jsonObject.addProperty("component_appsecret", getWxOpenConfigStorage().getComponentAppSecret());
117126
jsonObject.addProperty("component_verify_ticket", getWxOpenConfigStorage().getComponentVerifyTicket());
118127

119128
String responseContent = this.getWxOpenService().post(API_COMPONENT_TOKEN_URL, jsonObject.toString());
120129
WxOpenComponentAccessToken componentAccessToken = WxOpenComponentAccessToken.fromJson(responseContent);
121-
getWxOpenConfigStorage().updateComponentAccessToken(componentAccessToken);
130+
config.updateComponentAccessToken(componentAccessToken);
131+
return config.getComponentAccessToken();
132+
} finally {
133+
lock.unlock();
122134
}
123-
return this.getWxOpenConfigStorage().getComponentAccessToken();
124135
}
125136

126137
@Override
@@ -346,18 +357,28 @@ public void setAuthorizerOption(String authorizerAppid, String optionName, Strin
346357

347358
@Override
348359
public String getAuthorizerAccessToken(String appId, boolean forceRefresh) throws WxErrorException {
349-
350-
if (this.getWxOpenConfigStorage().isAuthorizerAccessTokenExpired(appId) || forceRefresh) {
360+
WxOpenConfigStorage config = getWxOpenConfigStorage();
361+
if (!config.isAuthorizerAccessTokenExpired(appId) && !forceRefresh){
362+
return config.getAuthorizerAccessToken(appId);
363+
}
364+
Lock lock = config.getWxMpConfigStorage(appId).getAccessTokenLock();
365+
lock.lock();
366+
try{
367+
if (!config.isAuthorizerAccessTokenExpired(appId) && !forceRefresh){
368+
return config.getAuthorizerAccessToken(appId);
369+
}
351370
JsonObject jsonObject = new JsonObject();
352371
jsonObject.addProperty("component_appid", getWxOpenConfigStorage().getComponentAppId());
353372
jsonObject.addProperty("authorizer_appid", appId);
354373
jsonObject.addProperty("authorizer_refresh_token", getWxOpenConfigStorage().getAuthorizerRefreshToken(appId));
355374
String responseContent = post(API_AUTHORIZER_TOKEN_URL, jsonObject.toString());
356375

357376
WxOpenAuthorizerAccessToken wxOpenAuthorizerAccessToken = WxOpenAuthorizerAccessToken.fromJson(responseContent);
358-
getWxOpenConfigStorage().updateAuthorizerAccessToken(appId, wxOpenAuthorizerAccessToken);
377+
config.updateAuthorizerAccessToken(appId, wxOpenAuthorizerAccessToken);
378+
return config.getAuthorizerAccessToken(appId);
379+
}finally {
380+
lock.unlock();
359381
}
360-
return this.getWxOpenConfigStorage().getAuthorizerAccessToken(appId);
361382
}
362383

363384
@Override

weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage {
4444
private Map<String, Token> authorizerAccessTokens = new ConcurrentHashMap<>();
4545
private Map<String, Token> jsapiTickets = new ConcurrentHashMap<>();
4646
private Map<String, Token> cardApiTickets = new ConcurrentHashMap<>();
47+
private Map<String, Lock> locks = new ConcurrentHashMap<>();
48+
49+
private Lock componentAccessTokenLock = getLockByKey("componentAccessTokenLock");
4750

4851

4952
@Override
@@ -61,6 +64,21 @@ public void updateComponentAccessToken(WxOpenComponentAccessToken componentAcces
6164
updateComponentAccessToken(componentAccessToken.getComponentAccessToken(), componentAccessToken.getExpiresIn());
6265
}
6366

67+
@Override
68+
public Lock getLockByKey(String key){
69+
Lock lock = locks.get(key);
70+
if (lock == null) {
71+
synchronized (WxOpenInMemoryConfigStorage.class){
72+
lock = locks.get(key);
73+
if (lock == null) {
74+
lock = new ReentrantLock();
75+
locks.put(key, lock);
76+
}
77+
}
78+
}
79+
return lock;
80+
}
81+
6482
@Override
6583
public WxMpConfigStorage getWxMpConfigStorage(String appId) {
6684
return new WxOpenInnerConfigStorage(this, appId);
@@ -211,13 +229,16 @@ private static class WxOpenInnerConfigStorage implements WxMpConfigStorage, WxMa
211229
* 云环境ID
212230
*/
213231
private volatile String cloudEnv;
214-
private Lock accessTokenLock = new ReentrantLock();
215-
private Lock jsapiTicketLock = new ReentrantLock();
216-
private Lock cardApiTicketLock = new ReentrantLock();
232+
private final Lock accessTokenLock;
233+
private final Lock jsapiTicketLock;
234+
private final Lock cardApiTicketLock;
217235

218236
private WxOpenInnerConfigStorage(WxOpenConfigStorage wxOpenConfigStorage, String appId) {
219237
this.wxOpenConfigStorage = wxOpenConfigStorage;
220238
this.appId = appId;
239+
this.accessTokenLock = wxOpenConfigStorage.getLockByKey(appId + ":accessTokenLock");
240+
this.jsapiTicketLock = wxOpenConfigStorage.getLockByKey(appId + ":jsapiTicketLock");
241+
this.cardApiTicketLock = wxOpenConfigStorage.getLockByKey(appId + ":cardApiTicketLock");
221242
}
222243

223244
@Override

weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInRedisConfigStorage.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package me.chanjar.weixin.open.api.impl;
22

3+
import me.chanjar.weixin.common.util.locks.JedisDistributedLock;
34
import redis.clients.jedis.Jedis;
45
import redis.clients.jedis.JedisPool;
56
import redis.clients.util.Pool;
67

8+
import java.util.concurrent.locks.Lock;
9+
710
/**
811
* @author <a href="https://github.com/007gzs">007</a>
912
*/
@@ -163,4 +166,9 @@ public void updateCardApiTicket(String appId, String cardApiTicket, int expiresI
163166
jedis.setex(this.getKey(this.cardApiTicket, appId), expiresInSeconds - 200, cardApiTicket);
164167
}
165168
}
169+
170+
@Override
171+
public Lock getLockByKey(String key) {
172+
return new JedisDistributedLock(jedisPool, getKey(lockKey, key));
173+
}
166174
}

0 commit comments

Comments
 (0)