Browse Source

Merge pull request #82 from iwareserictsai/develop

修改Token/Ticket的同步机制以支持集群
master
Binary Wang 8 years ago
committed by GitHub
parent
commit
6278161f23
4 changed files with 96 additions and 71 deletions
  1. +7
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java
  2. +21
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java
  3. +19
    -19
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java
  4. +49
    -52
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java

+ 7
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java View File

@@ -5,6 +5,7 @@ import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder;


import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
import java.io.File; import java.io.File;
import java.util.concurrent.locks.Lock;


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


String getAccessToken(); String getAccessToken();


Lock getAccessTokenLock();

boolean isAccessTokenExpired(); boolean isAccessTokenExpired();


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


String getJsapiTicket(); String getJsapiTicket();


Lock getJsapiTicketLock();

boolean isJsapiTicketExpired(); boolean isJsapiTicketExpired();


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


String getCardApiTicket(); String getCardApiTicket();


Lock getCardApiTicketLock();

boolean isCardApiTicketExpired(); boolean isCardApiTicketExpired();


/** /**


+ 21
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java View File

@@ -6,6 +6,8 @@ import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder;


import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
import java.io.File; import java.io.File;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


/** /**
* 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化 * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化
@@ -36,6 +38,10 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
protected volatile String cardApiTicket; protected volatile String cardApiTicket;
protected volatile long cardApiTicketExpiresTime; 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; return this.accessToken;
} }


@Override
public Lock getAccessTokenLock() {
return this.accessTokenLock;
}

@Override @Override
public boolean isAccessTokenExpired() { public boolean isAccessTokenExpired() {
return System.currentTimeMillis() > this.expiresTime; return System.currentTimeMillis() > this.expiresTime;
@@ -76,6 +87,11 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
return this.jsapiTicket; return this.jsapiTicket;
} }


@Override
public Lock getJsapiTicketLock() {
return this.jsapiTicketLock;
}

public void setJsapiTicket(String jsapiTicket) { public void setJsapiTicket(String jsapiTicket) {
this.jsapiTicket = jsapiTicket; this.jsapiTicket = jsapiTicket;
} }
@@ -113,6 +129,11 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
return this.cardApiTicket; return this.cardApiTicket;
} }


@Override
public Lock getCardApiTicketLock() {
return this.cardApiTicketLock;
}

@Override @Override
public boolean isCardApiTicketExpired() { public boolean isCardApiTicketExpired() {
return System.currentTimeMillis() > this.cardApiTicketExpiresTime; return System.currentTimeMillis() > this.cardApiTicketExpiresTime;


+ 19
- 19
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java View File

@@ -1,6 +1,7 @@
package me.chanjar.weixin.mp.api.impl; package me.chanjar.weixin.mp.api.impl;


import java.util.Arrays; import java.util.Arrays;
import java.util.concurrent.locks.Lock;


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


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


/**
* 全局的是否正在刷新卡券api_ticket的锁
*/
private final Object globalCardApiTicketRefreshLock = new Object();

private WxMpService wxMpService; private WxMpService wxMpService;


public WxMpCardServiceImpl(WxMpService wxMpService) { public WxMpCardServiceImpl(WxMpService wxMpService) {
@@ -66,21 +62,25 @@ public class WxMpCardServiceImpl implements WxMpCardService {
*/ */
@Override @Override
public String getCardApiTicket(boolean forceRefresh) throws WxErrorException { 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(); return this.wxMpService.getWxMpConfigStorage().getCardApiTicket();
} }


+ 49
- 52
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java View File

@@ -28,6 +28,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;


import java.io.IOException; import java.io.IOException;
import java.util.concurrent.locks.Lock;


public class WxMpServiceImpl implements WxMpService { public class WxMpServiceImpl implements WxMpService {


@@ -35,16 +36,6 @@ public class WxMpServiceImpl implements WxMpService {


protected final Logger log = LoggerFactory.getLogger(this.getClass()); 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 WxMpConfigStorage configStorage;


private WxMpKefuService kefuService = new WxMpKefuServiceImpl(this); private WxMpKefuService kefuService = new WxMpKefuServiceImpl(this);
@@ -98,39 +89,42 @@ public class WxMpServiceImpl implements WxMpService {


@Override @Override
public String getAccessToken(boolean forceRefresh) throws WxErrorException { 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(); return this.configStorage.getAccessToken();
} }
@@ -142,22 +136,25 @@ public class WxMpServiceImpl implements WxMpService {


@Override @Override
public String getJsapiTicket(boolean forceRefresh) throws WxErrorException { 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(); return this.configStorage.getJsapiTicket();
} }


Loading…
Cancel
Save