更新集群模式多次重复获取微信accessToken的问题

This commit is contained in:
OPGame
2019-08-09 16:34:38 +08:00
parent 715d7f1eb7
commit 86954f17d8
5 changed files with 191 additions and 3 deletions

View File

@@ -45,5 +45,5 @@ public @interface RedisLock {
*
* @return 秒
*/
TimeUnit timeUnit() default TimeUnit.SECONDS;
TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
}

View File

@@ -0,0 +1,89 @@
package com.yami.shop.mp.component;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import com.yami.shop.common.exception.YamiShopBindException;
import me.chanjar.weixin.common.bean.WxAccessToken;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicResponseHandler;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
/**
* WxMaServiceImpl 在集群模式获取accessToken的方式
* @author LGH
*/
public class WxMaServiceClusterImpl extends WxMaServiceImpl {
private static final String REDISSON_LOCK_PREFIX = "redisson_lock:";
private RedissonClient redissonClient;
public void setRedissonClient(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
@Override
public String getAccessToken(boolean forceRefresh) throws WxErrorException {
if (!this.getWxMaConfig().isAccessTokenExpired() && !forceRefresh) {
return this.getWxMaConfig().getAccessToken();
}
RLock rLock = redissonClient.getLock(REDISSON_LOCK_PREFIX + ":WxMaServiceCluster:getAccessToken");
boolean doingUpdateAccessToken;
try {
doingUpdateAccessToken = rLock.tryLock(10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
return this.getWxMaConfig().getAccessToken();
}
if (!doingUpdateAccessToken) {
throw new YamiShopBindException("服务器繁忙,请稍后再试");
}
if (this.getWxMaConfig().isAccessTokenExpired()) {
return this.getWxMaConfig().getAccessToken();
}
try {
String url = String.format(WxMaService.GET_ACCESS_TOKEN_URL, this.getWxMaConfig().getAppid(),
this.getWxMaConfig().getSecret());
try {
HttpGet httpGet = new HttpGet(url);
if (this.getRequestHttpProxy() != null) {
RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
httpGet.setConfig(config);
}
try (CloseableHttpResponse response = getRequestHttpClient().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.getWxMaConfig().updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
return this.getWxMaConfig().getAccessToken();
} finally {
httpGet.releaseConnection();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
} finally {
rLock.unlock();
}
}
}

View File

@@ -0,0 +1,90 @@
package com.yami.shop.mp.component;
import com.yami.shop.common.exception.YamiShopBindException;
import me.chanjar.weixin.common.WxType;
import me.chanjar.weixin.common.bean.WxAccessToken;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicResponseHandler;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
/**
* WxMpServiceImpl 在集群模式获取accessToken的方式
* @author LGH
*/
public class WxMpServiceClusterImpl extends WxMpServiceImpl {
private static final String REDISSON_LOCK_PREFIX = "redisson_lock:";
private RedissonClient redissonClient;
public void setRedissonClient(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
@Override
public String getAccessToken(boolean forceRefresh) throws WxErrorException {
if (!this.getWxMpConfigStorage().isAccessTokenExpired() && !forceRefresh) {
return this.getWxMpConfigStorage().getAccessToken();
}
RLock rLock = redissonClient.getLock(REDISSON_LOCK_PREFIX + ":WxMpServiceCluster:getAccessToken");
boolean doingUpdateAccessToken;
try {
doingUpdateAccessToken = rLock.tryLock(10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
return this.getWxMpConfigStorage().getAccessToken();
}
if (!doingUpdateAccessToken) {
throw new YamiShopBindException("服务器繁忙,请稍后再试");
}
if (this.getWxMpConfigStorage().isAccessTokenExpired()) {
return this.getWxMpConfigStorage().getAccessToken();
}
Object result = null;
try {
String url = String.format(WxMpService.GET_ACCESS_TOKEN_URL,
this.getWxMpConfigStorage().getAppId(), this.getWxMpConfigStorage().getSecret());
try {
HttpGet httpGet = new HttpGet(url);
if (this.getRequestHttpProxy() != null) {
RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
httpGet.setConfig(config);
}
try (CloseableHttpResponse response = getRequestHttpClient().execute(httpGet)) {
String resultContent = new BasicResponseHandler().handleResponse(response);
WxError error = WxError.fromJson(resultContent, WxType.MP);
if (error.getErrorCode() != 0) {
throw new WxErrorException(error);
}
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
this.getWxMpConfigStorage().updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
return this.getWxMpConfigStorage().getAccessToken();
} finally {
httpGet.releaseConnection();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
} finally {
rLock.unlock();
}
}
}

View File

@@ -13,7 +13,9 @@ package com.yami.shop.mp.config;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import com.yami.shop.mp.component.WxMaInRedisConfig;
import com.yami.shop.mp.component.WxMaServiceClusterImpl;
import lombok.AllArgsConstructor;
import org.redisson.api.RedissonClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -30,10 +32,13 @@ public class WxMaConfiguration {
private final WxMaInRedisConfig wxMaInRedisConfig;
private final RedissonClient redissonClient;
@Bean
public WxMaService wxMaService() {
WxMaService service = new WxMaServiceImpl();
WxMaServiceClusterImpl service = new WxMaServiceClusterImpl();
service.setWxMaConfig(wxMaInRedisConfig);
service.setRedissonClient(redissonClient);
return service;
}

View File

@@ -11,11 +11,13 @@
package com.yami.shop.mp.config;
import com.yami.shop.mp.component.WxMpInRedisConfigStorage;
import com.yami.shop.mp.component.WxMpServiceClusterImpl;
import com.yami.shop.mp.handler.MenuHandler;
import lombok.AllArgsConstructor;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import org.redisson.api.RedissonClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -34,11 +36,13 @@ public class WxMpConfiguration {
private final MenuHandler menuHandler;
private final WxMpInRedisConfigStorage wxMpInRedisConfigStorage;
private final RedissonClient redissonClient;
@Bean
public WxMpService wxMpService() {
WxMpService service = new WxMpServiceImpl();
WxMpServiceClusterImpl service = new WxMpServiceClusterImpl();
service.setWxMpConfigStorage(wxMpInRedisConfigStorage);
service.setRedissonClient(redissonClient);
return service;
}