Skip to content

Commit 0acde03

Browse files
committed
修改获取Token/Ticket时的同步机制,改由通过锁来进行同步,由WxMpConfigStorage来提供锁实现。
1 parent 72d6aad commit 0acde03

File tree

4 files changed

+96
-71
lines changed

4 files changed

+96
-71
lines changed

weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import javax.net.ssl.SSLContext;
77
import java.io.File;
8+
import java.util.concurrent.locks.Lock;
89

910
/**
1011
* 微信客户端配置存储
@@ -15,6 +16,8 @@ public interface WxMpConfigStorage {
1516

1617
String getAccessToken();
1718

19+
Lock getAccessTokenLock();
20+
1821
boolean isAccessTokenExpired();
1922

2023
/**
@@ -37,6 +40,8 @@ public interface WxMpConfigStorage {
3740

3841
String getJsapiTicket();
3942

43+
Lock getJsapiTicketLock();
44+
4045
boolean isJsapiTicketExpired();
4146

4247
/**
@@ -53,6 +58,8 @@ public interface WxMpConfigStorage {
5358

5459
String getCardApiTicket();
5560

61+
Lock getCardApiTicketLock();
62+
5663
boolean isCardApiTicketExpired();
5764

5865
/**

weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java

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

77
import javax.net.ssl.SSLContext;
88
import java.io.File;
9+
import java.util.concurrent.locks.Lock;
10+
import java.util.concurrent.locks.ReentrantLock;
911

1012
/**
1113
* 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化
@@ -36,6 +38,10 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
3638
protected volatile String cardApiTicket;
3739
protected volatile long cardApiTicketExpiresTime;
3840

41+
protected Lock accessTokenLock = new ReentrantLock();
42+
protected Lock jsapiTicketLock = new ReentrantLock();
43+
protected Lock cardApiTicketLock = new ReentrantLock();
44+
3945
/**
4046
* 临时文件目录
4147
*/
@@ -50,6 +56,11 @@ public String getAccessToken() {
5056
return this.accessToken;
5157
}
5258

59+
@Override
60+
public Lock getAccessTokenLock() {
61+
return this.accessTokenLock;
62+
}
63+
5364
@Override
5465
public boolean isAccessTokenExpired() {
5566
return System.currentTimeMillis() > this.expiresTime;
@@ -76,6 +87,11 @@ public String getJsapiTicket() {
7687
return this.jsapiTicket;
7788
}
7889

90+
@Override
91+
public Lock getJsapiTicketLock() {
92+
return this.jsapiTicketLock;
93+
}
94+
7995
public void setJsapiTicket(String jsapiTicket) {
8096
this.jsapiTicket = jsapiTicket;
8197
}
@@ -113,6 +129,11 @@ public String getCardApiTicket() {
113129
return this.cardApiTicket;
114130
}
115131

132+
@Override
133+
public Lock getCardApiTicketLock() {
134+
return this.cardApiTicketLock;
135+
}
136+
116137
@Override
117138
public boolean isCardApiTicketExpired() {
118139
return System.currentTimeMillis() > this.cardApiTicketExpiresTime;

weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package me.chanjar.weixin.mp.api.impl;
22

33
import java.util.Arrays;
4+
import java.util.concurrent.locks.Lock;
45

56
import org.slf4j.Logger;
67
import org.slf4j.LoggerFactory;
@@ -29,11 +30,6 @@ public class WxMpCardServiceImpl implements WxMpCardService {
2930

3031
private final Logger log = LoggerFactory.getLogger(WxMpCardServiceImpl.class);
3132

32-
/**
33-
* 全局的是否正在刷新卡券api_ticket的锁
34-
*/
35-
private final Object globalCardApiTicketRefreshLock = new Object();
36-
3733
private WxMpService wxMpService;
3834

3935
public WxMpCardServiceImpl(WxMpService wxMpService) {
@@ -66,21 +62,25 @@ public String getCardApiTicket() throws WxErrorException {
6662
*/
6763
@Override
6864
public String getCardApiTicket(boolean forceRefresh) throws WxErrorException {
69-
if (forceRefresh) {
70-
this.wxMpService.getWxMpConfigStorage().expireCardApiTicket();
71-
}
72-
if (this.wxMpService.getWxMpConfigStorage().isCardApiTicketExpired()) {
73-
synchronized (this.globalCardApiTicketRefreshLock) {
74-
if (this.wxMpService.getWxMpConfigStorage().isCardApiTicketExpired()) {
75-
String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card";
76-
String responseContent = this.wxMpService.execute(new SimpleGetRequestExecutor(), url, null);
77-
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
78-
JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject();
79-
String cardApiTicket = tmpJsonObject.get("ticket").getAsString();
80-
int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt();
81-
this.wxMpService.getWxMpConfigStorage().updateCardApiTicket(cardApiTicket, expiresInSeconds);
82-
}
65+
Lock lock = wxMpService.getWxMpConfigStorage().getCardApiTicketLock();
66+
try {
67+
lock.lock();
68+
69+
if (forceRefresh) {
70+
this.wxMpService.getWxMpConfigStorage().expireCardApiTicket();
71+
}
72+
73+
if (this.wxMpService.getWxMpConfigStorage().isCardApiTicketExpired()) {
74+
String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card";
75+
String responseContent = this.wxMpService.execute(new SimpleGetRequestExecutor(), url, null);
76+
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
77+
JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject();
78+
String cardApiTicket = tmpJsonObject.get("ticket").getAsString();
79+
int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt();
80+
this.wxMpService.getWxMpConfigStorage().updateCardApiTicket(cardApiTicket, expiresInSeconds);
8381
}
82+
} finally {
83+
lock.unlock();
8484
}
8585
return this.wxMpService.getWxMpConfigStorage().getCardApiTicket();
8686
}

weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java

Lines changed: 49 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -28,23 +28,14 @@
2828
import org.slf4j.LoggerFactory;
2929

3030
import java.io.IOException;
31+
import java.util.concurrent.locks.Lock;
3132

3233
public class WxMpServiceImpl implements WxMpService {
3334

3435
private static final JsonParser JSON_PARSER = new JsonParser();
3536

3637
protected final Logger log = LoggerFactory.getLogger(this.getClass());
3738

38-
/**
39-
* 全局的是否正在刷新access token的锁
40-
*/
41-
private final Object globalAccessTokenRefreshLock = new Object();
42-
43-
/**
44-
* 全局的是否正在刷新jsapi_ticket的锁
45-
*/
46-
private final Object globalJsapiTicketRefreshLock = new Object();
47-
4839
private WxMpConfigStorage configStorage;
4940

5041
private WxMpKefuService kefuService = new WxMpKefuServiceImpl(this);
@@ -98,39 +89,42 @@ public String getAccessToken() throws WxErrorException {
9889

9990
@Override
10091
public String getAccessToken(boolean forceRefresh) throws WxErrorException {
101-
if (forceRefresh) {
102-
this.configStorage.expireAccessToken();
103-
}
92+
Lock lock = configStorage.getAccessTokenLock();
93+
try {
94+
lock.lock();
10495

105-
if (this.configStorage.isAccessTokenExpired()) {
106-
synchronized (this.globalAccessTokenRefreshLock) {
107-
if (this.configStorage.isAccessTokenExpired()) {
108-
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential" +
109-
"&appid=" + this.configStorage.getAppId() + "&secret="
110-
+ this.configStorage.getSecret();
111-
try {
112-
HttpGet httpGet = new HttpGet(url);
113-
if (this.httpProxy != null) {
114-
RequestConfig config = RequestConfig.custom().setProxy(this.httpProxy).build();
115-
httpGet.setConfig(config);
116-
}
117-
try (CloseableHttpResponse response = getHttpclient().execute(httpGet)) {
118-
String resultContent = new BasicResponseHandler().handleResponse(response);
119-
WxError error = WxError.fromJson(resultContent);
120-
if (error.getErrorCode() != 0) {
121-
throw new WxErrorException(error);
122-
}
123-
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
124-
this.configStorage.updateAccessToken(accessToken.getAccessToken(),
125-
accessToken.getExpiresIn());
126-
}finally {
127-
httpGet.releaseConnection();
96+
if (forceRefresh) {
97+
this.configStorage.expireAccessToken();
98+
}
99+
100+
if (this.configStorage.isAccessTokenExpired()) {
101+
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential" +
102+
"&appid=" + this.configStorage.getAppId() + "&secret="
103+
+ this.configStorage.getSecret();
104+
try {
105+
HttpGet httpGet = new HttpGet(url);
106+
if (this.httpProxy != null) {
107+
RequestConfig config = RequestConfig.custom().setProxy(this.httpProxy).build();
108+
httpGet.setConfig(config);
109+
}
110+
try (CloseableHttpResponse response = getHttpclient().execute(httpGet)) {
111+
String resultContent = new BasicResponseHandler().handleResponse(response);
112+
WxError error = WxError.fromJson(resultContent);
113+
if (error.getErrorCode() != 0) {
114+
throw new WxErrorException(error);
128115
}
129-
} catch (IOException e) {
130-
throw new RuntimeException(e);
116+
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
117+
this.configStorage.updateAccessToken(accessToken.getAccessToken(),
118+
accessToken.getExpiresIn());
119+
}finally {
120+
httpGet.releaseConnection();
131121
}
122+
} catch (IOException e) {
123+
throw new RuntimeException(e);
132124
}
133125
}
126+
} finally {
127+
lock.unlock();
134128
}
135129
return this.configStorage.getAccessToken();
136130
}
@@ -142,22 +136,25 @@ public String getJsapiTicket() throws WxErrorException {
142136

143137
@Override
144138
public String getJsapiTicket(boolean forceRefresh) throws WxErrorException {
145-
if (forceRefresh) {
146-
this.configStorage.expireJsapiTicket();
147-
}
139+
Lock lock = configStorage.getJsapiTicketLock();
140+
try {
141+
lock.lock();
148142

149-
if (this.configStorage.isJsapiTicketExpired()) {
150-
synchronized (this.globalJsapiTicketRefreshLock) {
151-
if (this.configStorage.isJsapiTicketExpired()) {
152-
String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi";
153-
String responseContent = execute(new SimpleGetRequestExecutor(), url, null);
154-
JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent);
155-
JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject();
156-
String jsapiTicket = tmpJsonObject.get("ticket").getAsString();
157-
int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt();
158-
this.configStorage.updateJsapiTicket(jsapiTicket, expiresInSeconds);
159-
}
143+
if (forceRefresh) {
144+
this.configStorage.expireJsapiTicket();
145+
}
146+
147+
if (this.configStorage.isJsapiTicketExpired()) {
148+
String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi";
149+
String responseContent = execute(new SimpleGetRequestExecutor(), url, null);
150+
JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent);
151+
JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject();
152+
String jsapiTicket = tmpJsonObject.get("ticket").getAsString();
153+
int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt();
154+
this.configStorage.updateJsapiTicket(jsapiTicket, expiresInSeconds);
160155
}
156+
} finally {
157+
lock.unlock();
161158
}
162159
return this.configStorage.getJsapiTicket();
163160
}

0 commit comments

Comments
 (0)