From 1daf3a63a1051d4d5d81bc792e57a01a1ae08478 Mon Sep 17 00:00:00 2001 From: Daniel Qian Date: Tue, 20 Jan 2015 14:13:11 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20CP=20=E8=B0=83=E6=95=B4access=20tok?= =?UTF-8?q?en=E5=88=B7=E6=96=B0=E7=AD=96=E7=95=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/cp/api/WxCpConfigStorage.java | 18 +++-- .../cp/api/WxCpInMemoryConfigStorage.java | 32 +++++--- .../me/chanjar/weixin/cp/api/WxCpService.java | 3 +- .../weixin/cp/api/WxCpServiceImpl.java | 76 ++++++++----------- .../weixin/cp/api/WxCpBaseAPITest.java | 2 +- .../demo/WxCpDemoInMemoryConfigStorage.java | 2 +- 6 files changed, 69 insertions(+), 64 deletions(-) diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpConfigStorage.java index 36c9cfba..44123a36 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpConfigStorage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpConfigStorage.java @@ -9,12 +9,20 @@ import me.chanjar.weixin.common.bean.WxAccessToken; */ public interface WxCpConfigStorage { + public String getAccessToken(); + + public boolean isAccessTokenExpired(); + + /** + * 强制将access token过期掉 + */ + public void expireAccessToken(); + public void updateAccessToken(WxAccessToken accessToken); - + public void updateAccessToken(String accessToken, int expiresIn); - - public String getAccessToken(); - + + public String getCorpId(); public String getCorpSecret(); @@ -25,7 +33,7 @@ public interface WxCpConfigStorage { public String getAesKey(); - public int getExpiresIn(); + public long getExpiresTime(); public String getOauth2redirectUri(); diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpInMemoryConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpInMemoryConfigStorage.java index 9ff1f187..dd4882e2 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpInMemoryConfigStorage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpInMemoryConfigStorage.java @@ -16,7 +16,7 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage { protected String accessToken; protected String aesKey; protected String agentId; - protected int expiresIn; + protected long expiresTime; protected String oauth2redirectUri; @@ -25,17 +25,25 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage { protected String http_proxy_username; protected String http_proxy_password; + public String getAccessToken() { + return this.accessToken; + } + + public boolean isAccessTokenExpired() { + return System.currentTimeMillis() > this.expiresTime; + } + + public void expireAccessToken() { + this.expiresTime = 0; + } + public void updateAccessToken(WxAccessToken accessToken) { updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); } - public void updateAccessToken(String accessToken, int expiresIn) { + public void updateAccessToken(String accessToken, int expiresInSeconds) { this.accessToken = accessToken; - this.expiresIn = expiresIn; - } - - public String getAccessToken() { - return this.accessToken; + this.expiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000l; } public String getCorpId() { @@ -50,8 +58,8 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage { return this.token; } - public int getExpiresIn() { - return this.expiresIn; + public long getExpiresTime() { + return this.expiresTime; } public void setCorpId(String corpId) { @@ -78,8 +86,8 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage { this.accessToken = accessToken; } - public void setExpiresIn(int expiresIn) { - this.expiresIn = expiresIn; + public void setExpiresTime(long expiresTime) { + this.expiresTime = expiresTime; } public String getAgentId() { @@ -140,7 +148,7 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage { ", accessToken='" + accessToken + '\'' + ", aesKey='" + aesKey + '\'' + ", agentId='" + agentId + '\'' + - ", expiresIn=" + expiresIn + + ", expiresTime=" + expiresTime + ", http_proxy_host='" + http_proxy_host + '\'' + ", http_proxy_port=" + http_proxy_port + ", http_proxy_username='" + http_proxy_username + '\'' + diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java index 808eb6ce..c81bf715 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java @@ -52,9 +52,10 @@ public interface WxCpService { * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=获取access_token * * + * @return * @throws me.chanjar.weixin.common.exception.WxErrorException */ - public void accessTokenRefresh() throws WxErrorException; + public String getAccessToken() throws WxErrorException; /** *
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java
index 2e0738c7..c38ea65f 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java
@@ -46,11 +46,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
 public class WxCpServiceImpl implements WxCpService {
 
   /**
-   * 全局的是否正在刷新Access Token的flag
-   * true: 正在刷新
-   * false: 没有刷新
+   * 全局的是否正在刷新access token的锁
    */
-  protected static final AtomicBoolean GLOBAL_ACCESS_TOKEN_REFRESH_FLAG = new AtomicBoolean(false);
+  protected static final Object GLOBAL_ACCESS_TOKEN_REFRESH_LOCK = new Object();
 
   protected WxCpConfigStorage wxCpConfigStorage;
 
@@ -73,45 +71,37 @@ public class WxCpServiceImpl implements WxCpService {
     execute(new SimpleGetRequestExecutor(), url, null);
   }
 
-  public void accessTokenRefresh() throws WxErrorException {
-    if (!GLOBAL_ACCESS_TOKEN_REFRESH_FLAG.getAndSet(true)) {
-      try {
-        String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?"
-            + "&corpid=" + wxCpConfigStorage.getCorpId()
-            + "&corpsecret=" + wxCpConfigStorage.getCorpSecret();
-        try {
-          HttpGet httpGet = new HttpGet(url);
-          if (httpProxy != null) {
-            RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build();
-            httpGet.setConfig(config);
-          }
-          CloseableHttpClient httpclient = getHttpclient();
-          CloseableHttpResponse response = httpclient.execute(httpGet);
-          String resultContent = new BasicResponseHandler().handleResponse(response);
-          WxError error = WxError.fromJson(resultContent);
-          if (error.getErrorCode() != 0) {
-            throw new WxErrorException(error);
+  public String getAccessToken() throws WxErrorException {
+    if (wxCpConfigStorage.isAccessTokenExpired()) {
+      synchronized (GLOBAL_ACCESS_TOKEN_REFRESH_LOCK) {
+        if (wxCpConfigStorage.isAccessTokenExpired()) {
+          String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?"
+              + "&corpid=" + wxCpConfigStorage.getCorpId()
+              + "&corpsecret=" + wxCpConfigStorage.getCorpSecret();
+          try {
+            HttpGet httpGet = new HttpGet(url);
+            if (httpProxy != null) {
+              RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build();
+              httpGet.setConfig(config);
+            }
+            CloseableHttpClient httpclient = getHttpclient();
+            CloseableHttpResponse response = httpclient.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);
+            wxCpConfigStorage.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
+          } catch (ClientProtocolException e) {
+            throw new RuntimeException(e);
+          } catch (IOException e) {
+            throw new RuntimeException(e);
           }
-          WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
-          wxCpConfigStorage.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
-        } catch (ClientProtocolException e) {
-          throw new RuntimeException(e);
-        } catch (IOException e) {
-          throw new RuntimeException(e);
         }
-      } finally {
-        GLOBAL_ACCESS_TOKEN_REFRESH_FLAG.set(false);
       }
-    } else {
-      // 每隔100ms检查一下是否刷新完毕了
-      while (GLOBAL_ACCESS_TOKEN_REFRESH_FLAG.get()) {
-        try {
-          Thread.sleep(100);
-        } catch (InterruptedException e) {
-        }
-      }
-      // 刷新完毕了,就没他什么事儿了
     }
+    return wxCpConfigStorage.getAccessToken();
   }
 
   public void messageSend(WxCpMessage message) throws WxErrorException {
@@ -369,10 +359,7 @@ public class WxCpServiceImpl implements WxCpService {
    * @throws WxErrorException
    */
   public  T execute(RequestExecutor executor, String uri, E data) throws WxErrorException {
-    if (StringUtils.isBlank(wxCpConfigStorage.getAccessToken())) {
-      accessTokenRefresh();
-    }
-    String accessToken = wxCpConfigStorage.getAccessToken();
+    String accessToken = getAccessToken();
 
     String uriWithAccessToken = uri;
     uriWithAccessToken += uri.indexOf('?') == -1 ? "?access_token=" + accessToken : "&access_token=" + accessToken;
@@ -387,7 +374,8 @@ public class WxCpServiceImpl implements WxCpService {
        * 42001 access_token超时
        */
       if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001) {
-        accessTokenRefresh();
+        // 强制设置wxCpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token
+        wxCpConfigStorage.expireAccessToken();
         return execute(executor, uri, data);
       }
       /**
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBaseAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBaseAPITest.java
index 6ed438a9..606cca9b 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBaseAPITest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBaseAPITest.java
@@ -22,7 +22,7 @@ public class WxCpBaseAPITest {
   public void testRefreshAccessToken() throws WxErrorException {
     WxCpConfigStorage configStorage = wxService.wxCpConfigStorage;
     String before = configStorage.getAccessToken();
-    wxService.accessTokenRefresh();
+    wxService.getAccessToken();
 
     String after = configStorage.getAccessToken();
 
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoInMemoryConfigStorage.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoInMemoryConfigStorage.java
index 1d9103a5..52219868 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoInMemoryConfigStorage.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoInMemoryConfigStorage.java
@@ -16,7 +16,7 @@ class WxCpDemoInMemoryConfigStorage extends WxCpInMemoryConfigStorage {
   @Override
   public String toString() {
     return "SimpleWxConfigProvider [appidOrCorpid=" + corpId + ", corpSecret=" + corpSecret + ", accessToken=" + accessToken
-        + ", expiresIn=" + expiresIn + ", token=" + token + ", aesKey=" + aesKey + "]";
+        + ", expiresTime=" + expiresTime + ", token=" + token + ", aesKey=" + aesKey + "]";
   }