From 0acde0353f15af4e00298fee92546f6ef0fd603c Mon Sep 17 00:00:00 2001 From: "Eric.Tsai" Date: Mon, 21 Nov 2016 18:39:26 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=8E=B7=E5=8F=96Token/Ticke?= =?UTF-8?q?t=E6=97=B6=E7=9A=84=E5=90=8C=E6=AD=A5=E6=9C=BA=E5=88=B6?= =?UTF-8?q?=EF=BC=8C=E6=94=B9=E7=94=B1=E9=80=9A=E8=BF=87=E9=94=81=E6=9D=A5?= =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E5=90=8C=E6=AD=A5=EF=BC=8C=E7=94=B1WxMpConfi?= =?UTF-8?q?gStorage=E6=9D=A5=E6=8F=90=E4=BE=9B=E9=94=81=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/mp/api/WxMpConfigStorage.java | 7 ++ .../mp/api/WxMpInMemoryConfigStorage.java | 21 ++++ .../mp/api/impl/WxMpCardServiceImpl.java | 38 +++---- .../weixin/mp/api/impl/WxMpServiceImpl.java | 101 +++++++++--------- 4 files changed, 96 insertions(+), 71 deletions(-) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java index 67d39a78..78b1a587 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java @@ -5,6 +5,7 @@ import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder; import javax.net.ssl.SSLContext; import java.io.File; +import java.util.concurrent.locks.Lock; /** * 微信客户端配置存储 @@ -15,6 +16,8 @@ public interface WxMpConfigStorage { String getAccessToken(); + Lock getAccessTokenLock(); + boolean isAccessTokenExpired(); /** @@ -37,6 +40,8 @@ public interface WxMpConfigStorage { String getJsapiTicket(); + Lock getJsapiTicketLock(); + boolean isJsapiTicketExpired(); /** @@ -53,6 +58,8 @@ public interface WxMpConfigStorage { String getCardApiTicket(); + Lock getCardApiTicketLock(); + boolean isCardApiTicketExpired(); /** diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java index bb4a2985..e874e793 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java @@ -6,6 +6,8 @@ import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder; import javax.net.ssl.SSLContext; import java.io.File; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; /** * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化 @@ -36,6 +38,10 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { protected volatile String cardApiTicket; protected volatile long cardApiTicketExpiresTime; + protected Lock accessTokenLock = new ReentrantLock(); + protected Lock jsapiTicketLock = new ReentrantLock(); + protected Lock cardApiTicketLock = new ReentrantLock(); + /** * 临时文件目录 */ @@ -50,6 +56,11 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { return this.accessToken; } + @Override + public Lock getAccessTokenLock() { + return this.accessTokenLock; + } + @Override public boolean isAccessTokenExpired() { return System.currentTimeMillis() > this.expiresTime; @@ -76,6 +87,11 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { return this.jsapiTicket; } + @Override + public Lock getJsapiTicketLock() { + return this.jsapiTicketLock; + } + public void setJsapiTicket(String jsapiTicket) { this.jsapiTicket = jsapiTicket; } @@ -113,6 +129,11 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { return this.cardApiTicket; } + @Override + public Lock getCardApiTicketLock() { + return this.cardApiTicketLock; + } + @Override public boolean isCardApiTicketExpired() { return System.currentTimeMillis() > this.cardApiTicketExpiresTime; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java index 63e13809..2e6bf88e 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java @@ -1,6 +1,7 @@ package me.chanjar.weixin.mp.api.impl; import java.util.Arrays; +import java.util.concurrent.locks.Lock; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,11 +30,6 @@ public class WxMpCardServiceImpl implements WxMpCardService { private final Logger log = LoggerFactory.getLogger(WxMpCardServiceImpl.class); - /** - * 全局的是否正在刷新卡券api_ticket的锁 - */ - private final Object globalCardApiTicketRefreshLock = new Object(); - private WxMpService wxMpService; public WxMpCardServiceImpl(WxMpService wxMpService) { @@ -66,21 +62,25 @@ public class WxMpCardServiceImpl implements WxMpCardService { */ @Override public String getCardApiTicket(boolean forceRefresh) throws WxErrorException { - if (forceRefresh) { - this.wxMpService.getWxMpConfigStorage().expireCardApiTicket(); - } - if (this.wxMpService.getWxMpConfigStorage().isCardApiTicketExpired()) { - synchronized (this.globalCardApiTicketRefreshLock) { - if (this.wxMpService.getWxMpConfigStorage().isCardApiTicketExpired()) { - String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card"; - String responseContent = this.wxMpService.execute(new SimpleGetRequestExecutor(), url, null); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); - String cardApiTicket = tmpJsonObject.get("ticket").getAsString(); - int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); - this.wxMpService.getWxMpConfigStorage().updateCardApiTicket(cardApiTicket, expiresInSeconds); - } + Lock lock = wxMpService.getWxMpConfigStorage().getCardApiTicketLock(); + try { + lock.lock(); + + if (forceRefresh) { + this.wxMpService.getWxMpConfigStorage().expireCardApiTicket(); + } + + if (this.wxMpService.getWxMpConfigStorage().isCardApiTicketExpired()) { + String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card"; + String responseContent = this.wxMpService.execute(new SimpleGetRequestExecutor(), url, null); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); + String cardApiTicket = tmpJsonObject.get("ticket").getAsString(); + int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); + this.wxMpService.getWxMpConfigStorage().updateCardApiTicket(cardApiTicket, expiresInSeconds); } + } finally { + lock.unlock(); } return this.wxMpService.getWxMpConfigStorage().getCardApiTicket(); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java index 6a6044ab..3b8bf113 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java @@ -28,6 +28,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; +import java.util.concurrent.locks.Lock; public class WxMpServiceImpl implements WxMpService { @@ -35,16 +36,6 @@ public class WxMpServiceImpl implements WxMpService { protected final Logger log = LoggerFactory.getLogger(this.getClass()); - /** - * 全局的是否正在刷新access token的锁 - */ - private final Object globalAccessTokenRefreshLock = new Object(); - - /** - * 全局的是否正在刷新jsapi_ticket的锁 - */ - private final Object globalJsapiTicketRefreshLock = new Object(); - private WxMpConfigStorage configStorage; private WxMpKefuService kefuService = new WxMpKefuServiceImpl(this); @@ -98,39 +89,42 @@ public class WxMpServiceImpl implements WxMpService { @Override public String getAccessToken(boolean forceRefresh) throws WxErrorException { - if (forceRefresh) { - this.configStorage.expireAccessToken(); - } + Lock lock = configStorage.getAccessTokenLock(); + try { + lock.lock(); - if (this.configStorage.isAccessTokenExpired()) { - synchronized (this.globalAccessTokenRefreshLock) { - if (this.configStorage.isAccessTokenExpired()) { - String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential" + - "&appid=" + this.configStorage.getAppId() + "&secret=" - + this.configStorage.getSecret(); - try { - HttpGet httpGet = new HttpGet(url); - if (this.httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(this.httpProxy).build(); - httpGet.setConfig(config); - } - try (CloseableHttpResponse response = getHttpclient().execute(httpGet)) { - String resultContent = new BasicResponseHandler().handleResponse(response); - WxError error = WxError.fromJson(resultContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - WxAccessToken accessToken = WxAccessToken.fromJson(resultContent); - this.configStorage.updateAccessToken(accessToken.getAccessToken(), - accessToken.getExpiresIn()); - }finally { - httpGet.releaseConnection(); + if (forceRefresh) { + this.configStorage.expireAccessToken(); + } + + if (this.configStorage.isAccessTokenExpired()) { + String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential" + + "&appid=" + this.configStorage.getAppId() + "&secret=" + + this.configStorage.getSecret(); + try { + HttpGet httpGet = new HttpGet(url); + if (this.httpProxy != null) { + RequestConfig config = RequestConfig.custom().setProxy(this.httpProxy).build(); + httpGet.setConfig(config); + } + try (CloseableHttpResponse response = getHttpclient().execute(httpGet)) { + String resultContent = new BasicResponseHandler().handleResponse(response); + WxError error = WxError.fromJson(resultContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); } - } catch (IOException e) { - throw new RuntimeException(e); + WxAccessToken accessToken = WxAccessToken.fromJson(resultContent); + this.configStorage.updateAccessToken(accessToken.getAccessToken(), + accessToken.getExpiresIn()); + }finally { + httpGet.releaseConnection(); } + } catch (IOException e) { + throw new RuntimeException(e); } } + } finally { + lock.unlock(); } return this.configStorage.getAccessToken(); } @@ -142,22 +136,25 @@ public class WxMpServiceImpl implements WxMpService { @Override public String getJsapiTicket(boolean forceRefresh) throws WxErrorException { - if (forceRefresh) { - this.configStorage.expireJsapiTicket(); - } + Lock lock = configStorage.getJsapiTicketLock(); + try { + lock.lock(); - if (this.configStorage.isJsapiTicketExpired()) { - synchronized (this.globalJsapiTicketRefreshLock) { - if (this.configStorage.isJsapiTicketExpired()) { - String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi"; - String responseContent = execute(new SimpleGetRequestExecutor(), url, null); - JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); - JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); - String jsapiTicket = tmpJsonObject.get("ticket").getAsString(); - int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); - this.configStorage.updateJsapiTicket(jsapiTicket, expiresInSeconds); - } + if (forceRefresh) { + this.configStorage.expireJsapiTicket(); + } + + if (this.configStorage.isJsapiTicketExpired()) { + String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi"; + String responseContent = execute(new SimpleGetRequestExecutor(), url, null); + JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); + JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); + String jsapiTicket = tmpJsonObject.get("ticket").getAsString(); + int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); + this.configStorage.updateJsapiTicket(jsapiTicket, expiresInSeconds); } + } finally { + lock.unlock(); } return this.configStorage.getJsapiTicket(); }