Skip to content

Commit cb3f105

Browse files
yuanqixun袁启勋
andauthored
🆕 #1562企业微信自研应用增加Redisson的存储实现,支持分布式锁
* 企业微信自研应用,增加Redisson的存储实现,支持分布式锁 * 增加redisson的依赖。 Co-authored-by: 袁启勋 <[email protected]>
1 parent 6186d25 commit cb3f105

File tree

7 files changed

+316
-4
lines changed

7 files changed

+316
-4
lines changed

weixin-java-cp/pom.xml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@
3838
<groupId>org.slf4j</groupId>
3939
<artifactId>slf4j-api</artifactId>
4040
</dependency>
41-
41+
<!--分布式锁支持-->
42+
<dependency>
43+
<groupId>org.redisson</groupId>
44+
<artifactId>redisson</artifactId>
45+
</dependency>
4246
<dependency>
4347
<groupId>org.testng</groupId>
4448
<artifactId>testng</artifactId>
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,125 @@
11
package me.chanjar.weixin.cp.api.impl;
22

3+
import com.google.gson.JsonObject;
4+
import com.google.gson.JsonParser;
5+
import me.chanjar.weixin.common.WxType;
6+
import me.chanjar.weixin.common.bean.WxAccessToken;
7+
import me.chanjar.weixin.common.error.WxError;
8+
import me.chanjar.weixin.common.error.WxErrorException;
9+
import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
10+
import org.apache.http.client.config.RequestConfig;
11+
import org.apache.http.client.methods.CloseableHttpResponse;
12+
import org.apache.http.client.methods.HttpGet;
13+
import org.apache.http.impl.client.BasicResponseHandler;
14+
import org.apache.http.impl.client.CloseableHttpClient;
15+
16+
import java.io.IOException;
17+
import java.util.concurrent.locks.Lock;
18+
19+
import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.GET_AGENT_CONFIG_TICKET;
20+
import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.GET_JSAPI_TICKET;
21+
322
/**
423
* <pre>
524
* 默认接口实现类,使用apache httpclient实现
625
* Created by Binary Wang on 2017-5-27.
726
* </pre>
27+
* <pre>
28+
* 增加分布式锁(基于WxCpConfigStorage实现)的支持
29+
* Updated by yuanqixun on 2020-05-13
30+
* </pre>
31+
*
832
*
933
* @author <a href="https://github.com/binarywang">Binary Wang</a>
1034
*/
1135
public class WxCpServiceImpl extends WxCpServiceApacheHttpClientImpl {
36+
@Override
37+
public String getAccessToken(boolean forceRefresh) throws WxErrorException {
38+
if (!getWxCpConfigStorage().isAccessTokenExpired() && !forceRefresh) {
39+
return getWxCpConfigStorage().getAccessToken();
40+
}
41+
Lock lock = getWxCpConfigStorage().getAccessTokenLock();
42+
lock.lock();
43+
try {
44+
// 拿到锁之后,再次判断一下最新的token是否过期,避免重刷
45+
if (!getWxCpConfigStorage().isAccessTokenExpired() && !forceRefresh) {
46+
return getWxCpConfigStorage().getAccessToken();
47+
}
48+
String url = String.format(getWxCpConfigStorage().getApiUrl(WxCpApiPathConsts.GET_TOKEN), this.configStorage.getCorpId(), this.configStorage.getCorpSecret());
49+
try {
50+
HttpGet httpGet = new HttpGet(url);
51+
if (getRequestHttpProxy() != null) {
52+
RequestConfig config = RequestConfig.custom()
53+
.setProxy(getRequestHttpProxy()).build();
54+
httpGet.setConfig(config);
55+
}
56+
String resultContent;
57+
try (CloseableHttpClient httpClient = getRequestHttpClient();
58+
CloseableHttpResponse response = httpClient.execute(httpGet)) {
59+
resultContent = new BasicResponseHandler().handleResponse(response);
60+
} finally {
61+
httpGet.releaseConnection();
62+
}
63+
WxError error = WxError.fromJson(resultContent, WxType.CP);
64+
if (error.getErrorCode() != 0) {
65+
throw new WxErrorException(error);
66+
}
67+
68+
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
69+
getWxCpConfigStorage().updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
70+
} catch (IOException e) {
71+
throw new RuntimeException(e);
72+
}
73+
} finally {
74+
lock.unlock();
75+
}
76+
return getWxCpConfigStorage().getAccessToken();
77+
}
78+
79+
@Override
80+
public String getAgentJsapiTicket(boolean forceRefresh) throws WxErrorException {
81+
if (forceRefresh) {
82+
getWxCpConfigStorage().expireAgentJsapiTicket();
83+
}
84+
if (getWxCpConfigStorage().isAgentJsapiTicketExpired()) {
85+
Lock lock = getWxCpConfigStorage().getAgentJsapiTicketLock();
86+
lock.lock();
87+
try {
88+
// 拿到锁之后,再次判断一下最新的token是否过期,避免重刷
89+
if (getWxCpConfigStorage().isAgentJsapiTicketExpired()) {
90+
String responseContent = this.get(getWxCpConfigStorage().getApiUrl(GET_AGENT_CONFIG_TICKET), null);
91+
JsonObject jsonObject = new JsonParser().parse(responseContent).getAsJsonObject();
92+
getWxCpConfigStorage().updateAgentJsapiTicket(jsonObject.get("ticket").getAsString(),
93+
jsonObject.get("expires_in").getAsInt());
94+
}
95+
} finally {
96+
lock.unlock();
97+
}
98+
}
99+
return getWxCpConfigStorage().getAgentJsapiTicket();
100+
}
101+
102+
@Override
103+
public String getJsapiTicket(boolean forceRefresh) throws WxErrorException {
104+
if (forceRefresh) {
105+
getWxCpConfigStorage().expireJsapiTicket();
106+
}
107+
108+
if (getWxCpConfigStorage().isJsapiTicketExpired()) {
109+
Lock lock = getWxCpConfigStorage().getJsapiTicketLock();
110+
lock.lock();
111+
try {
112+
// 拿到锁之后,再次判断一下最新的token是否过期,避免重刷
113+
if (getWxCpConfigStorage().isJsapiTicketExpired()) {
114+
String responseContent = this.get(getWxCpConfigStorage().getApiUrl(GET_JSAPI_TICKET), null);
115+
JsonObject tmpJsonObject = new JsonParser().parse(responseContent).getAsJsonObject();
116+
getWxCpConfigStorage().updateJsapiTicket(tmpJsonObject.get("ticket").getAsString(),
117+
tmpJsonObject.get("expires_in").getAsInt());
118+
}
119+
} finally {
120+
lock.unlock();
121+
}
122+
}
123+
return getWxCpConfigStorage().getJsapiTicket();
124+
}
12125
}

weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpConfigStorage.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
55

66
import java.io.File;
7+
import java.util.concurrent.locks.Lock;
78

89
/**
910
* 微信客户端配置存储.
@@ -28,6 +29,8 @@ public interface WxCpConfigStorage {
2829

2930
String getAccessToken();
3031

32+
Lock getAccessTokenLock();
33+
3134
boolean isAccessTokenExpired();
3235

3336
/**
@@ -41,6 +44,8 @@ public interface WxCpConfigStorage {
4144

4245
String getJsapiTicket();
4346

47+
Lock getJsapiTicketLock();
48+
4449
boolean isJsapiTicketExpired();
4550

4651
/**
@@ -55,6 +60,8 @@ public interface WxCpConfigStorage {
5560

5661
String getAgentJsapiTicket();
5762

63+
Lock getAgentJsapiTicketLock();
64+
5865
boolean isAgentJsapiTicketExpired();
5966

6067
/**

weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpDefaultConfigImpl.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
import java.io.File;
1010
import java.io.Serializable;
11+
import java.util.concurrent.locks.Lock;
12+
import java.util.concurrent.locks.ReentrantLock;
1113

1214
/**
1315
* 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化.
@@ -22,6 +24,7 @@ public class WxCpDefaultConfigImpl implements WxCpConfigStorage, Serializable {
2224

2325
private volatile String token;
2426
protected volatile String accessToken;
27+
protected Lock accessTokenLock = new ReentrantLock();
2528
private volatile String aesKey;
2629
protected volatile Integer agentId;
2730
private volatile long expiresTime;
@@ -34,9 +37,11 @@ public class WxCpDefaultConfigImpl implements WxCpConfigStorage, Serializable {
3437
private volatile String httpProxyPassword;
3538

3639
private volatile String jsapiTicket;
40+
protected Lock jsapiTicketLock = new ReentrantLock();
3741
private volatile long jsapiTicketExpiresTime;
3842

3943
private volatile String agentJsapiTicket;
44+
protected Lock agentJsapiTicketLock = new ReentrantLock();
4045
private volatile long agentJsapiTicketExpiresTime;
4146

4247
private volatile File tmpDirFile;
@@ -63,6 +68,11 @@ public String getAccessToken() {
6368
return this.accessToken;
6469
}
6570

71+
@Override
72+
public Lock getAccessTokenLock() {
73+
return this.accessTokenLock;
74+
}
75+
6676
public void setAccessToken(String accessToken) {
6777
this.accessToken = accessToken;
6878
}
@@ -93,6 +103,11 @@ public String getJsapiTicket() {
93103
return this.jsapiTicket;
94104
}
95105

106+
@Override
107+
public Lock getJsapiTicketLock() {
108+
return this.jsapiTicketLock;
109+
}
110+
96111
public void setJsapiTicket(String jsapiTicket) {
97112
this.jsapiTicket = jsapiTicket;
98113
}
@@ -122,6 +137,11 @@ public String getAgentJsapiTicket() {
122137
return this.agentJsapiTicket;
123138
}
124139

140+
@Override
141+
public Lock getAgentJsapiTicketLock() {
142+
return this.agentJsapiTicketLock;
143+
}
144+
125145
@Override
126146
public boolean isAgentJsapiTicketExpired() {
127147
return System.currentTimeMillis() > this.agentJsapiTicketExpiresTime;

weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpRedisConfigImpl.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import redis.clients.jedis.JedisPoolConfig;
1010

1111
import java.io.File;
12+
import java.util.concurrent.locks.Lock;
13+
import java.util.concurrent.locks.ReentrantLock;
1214

1315
/**
1416
* <pre>
@@ -89,6 +91,11 @@ public String getAccessToken() {
8991
}
9092
}
9193

94+
@Override
95+
public Lock getAccessTokenLock() {
96+
return new ReentrantLock();
97+
}
98+
9299
@Override
93100
public boolean isAccessTokenExpired() {
94101
try (Jedis jedis = this.jedisPool.getResource()) {
@@ -132,6 +139,11 @@ public String getJsapiTicket() {
132139
}
133140
}
134141

142+
@Override
143+
public Lock getJsapiTicketLock() {
144+
return new ReentrantLock();
145+
}
146+
135147
@Override
136148
public boolean isJsapiTicketExpired() {
137149
try (Jedis jedis = this.jedisPool.getResource()) {
@@ -170,6 +182,11 @@ public String getAgentJsapiTicket() {
170182
}
171183
}
172184

185+
@Override
186+
public Lock getAgentJsapiTicketLock() {
187+
return new ReentrantLock();
188+
}
189+
173190
@Override
174191
public boolean isAgentJsapiTicketExpired() {
175192
try (Jedis jedis = this.jedisPool.getResource()) {

0 commit comments

Comments
 (0)