mirror of
				https://gitee.com/binary/weixin-java-tools.git
				synced 2025-10-31 10:38:42 +08:00 
			
		
		
		
	修改获取Token/Ticket时的同步机制,改由通过锁来进行同步,由WxMpConfigStorage来提供锁实现。
This commit is contained in:
		| @ -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(); | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|  | |||||||
| @ -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; | ||||||
|  | |||||||
| @ -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,11 +62,14 @@ public class WxMpCardServiceImpl implements WxMpCardService { | |||||||
|    */ |    */ | ||||||
|   @Override |   @Override | ||||||
|   public String getCardApiTicket(boolean forceRefresh) throws WxErrorException { |   public String getCardApiTicket(boolean forceRefresh) throws WxErrorException { | ||||||
|  |     Lock lock = wxMpService.getWxMpConfigStorage().getCardApiTicketLock(); | ||||||
|  |     try { | ||||||
|  |       lock.lock(); | ||||||
|  |  | ||||||
|       if (forceRefresh) { |       if (forceRefresh) { | ||||||
|         this.wxMpService.getWxMpConfigStorage().expireCardApiTicket(); |         this.wxMpService.getWxMpConfigStorage().expireCardApiTicket(); | ||||||
|       } |       } | ||||||
|     if (this.wxMpService.getWxMpConfigStorage().isCardApiTicketExpired()) { |  | ||||||
|       synchronized (this.globalCardApiTicketRefreshLock) { |  | ||||||
|       if (this.wxMpService.getWxMpConfigStorage().isCardApiTicketExpired()) { |       if (this.wxMpService.getWxMpConfigStorage().isCardApiTicketExpired()) { | ||||||
|         String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card"; |         String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card"; | ||||||
|         String responseContent = this.wxMpService.execute(new SimpleGetRequestExecutor(), url, null); |         String responseContent = this.wxMpService.execute(new SimpleGetRequestExecutor(), url, null); | ||||||
| @ -80,7 +79,8 @@ public class WxMpCardServiceImpl implements WxMpCardService { | |||||||
|         int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); |         int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); | ||||||
|         this.wxMpService.getWxMpConfigStorage().updateCardApiTicket(cardApiTicket, expiresInSeconds); |         this.wxMpService.getWxMpConfigStorage().updateCardApiTicket(cardApiTicket, expiresInSeconds); | ||||||
|       } |       } | ||||||
|       } |     } finally { | ||||||
|  |       lock.unlock(); | ||||||
|     } |     } | ||||||
|     return this.wxMpService.getWxMpConfigStorage().getCardApiTicket(); |     return this.wxMpService.getWxMpConfigStorage().getCardApiTicket(); | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -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,12 +89,14 @@ public class WxMpServiceImpl implements WxMpService { | |||||||
|  |  | ||||||
|   @Override |   @Override | ||||||
|   public String getAccessToken(boolean forceRefresh) throws WxErrorException { |   public String getAccessToken(boolean forceRefresh) throws WxErrorException { | ||||||
|  |     Lock lock = configStorage.getAccessTokenLock(); | ||||||
|  |     try { | ||||||
|  |       lock.lock(); | ||||||
|  |  | ||||||
|       if (forceRefresh) { |       if (forceRefresh) { | ||||||
|         this.configStorage.expireAccessToken(); |         this.configStorage.expireAccessToken(); | ||||||
|       } |       } | ||||||
|  |  | ||||||
|     if (this.configStorage.isAccessTokenExpired()) { |  | ||||||
|       synchronized (this.globalAccessTokenRefreshLock) { |  | ||||||
|       if (this.configStorage.isAccessTokenExpired()) { |       if (this.configStorage.isAccessTokenExpired()) { | ||||||
|         String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential" + |         String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential" + | ||||||
|             "&appid=" + this.configStorage.getAppId() + "&secret=" |             "&appid=" + this.configStorage.getAppId() + "&secret=" | ||||||
| @ -130,7 +123,8 @@ public class WxMpServiceImpl implements WxMpService { | |||||||
|           throw new RuntimeException(e); |           throw new RuntimeException(e); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|       } |     } finally { | ||||||
|  |       lock.unlock(); | ||||||
|     } |     } | ||||||
|     return this.configStorage.getAccessToken(); |     return this.configStorage.getAccessToken(); | ||||||
|   } |   } | ||||||
| @ -142,12 +136,14 @@ public class WxMpServiceImpl implements WxMpService { | |||||||
|  |  | ||||||
|   @Override |   @Override | ||||||
|   public String getJsapiTicket(boolean forceRefresh) throws WxErrorException { |   public String getJsapiTicket(boolean forceRefresh) throws WxErrorException { | ||||||
|  |     Lock lock = configStorage.getJsapiTicketLock(); | ||||||
|  |     try { | ||||||
|  |       lock.lock(); | ||||||
|  |  | ||||||
|       if (forceRefresh) { |       if (forceRefresh) { | ||||||
|         this.configStorage.expireJsapiTicket(); |         this.configStorage.expireJsapiTicket(); | ||||||
|       } |       } | ||||||
|  |  | ||||||
|     if (this.configStorage.isJsapiTicketExpired()) { |  | ||||||
|       synchronized (this.globalJsapiTicketRefreshLock) { |  | ||||||
|       if (this.configStorage.isJsapiTicketExpired()) { |       if (this.configStorage.isJsapiTicketExpired()) { | ||||||
|         String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi"; |         String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi"; | ||||||
|         String responseContent = execute(new SimpleGetRequestExecutor(), url, null); |         String responseContent = execute(new SimpleGetRequestExecutor(), url, null); | ||||||
| @ -157,7 +153,8 @@ public class WxMpServiceImpl implements WxMpService { | |||||||
|         int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); |         int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); | ||||||
|         this.configStorage.updateJsapiTicket(jsapiTicket, expiresInSeconds); |         this.configStorage.updateJsapiTicket(jsapiTicket, expiresInSeconds); | ||||||
|       } |       } | ||||||
|       } |     } finally { | ||||||
|  |       lock.unlock(); | ||||||
|     } |     } | ||||||
|     return this.configStorage.getJsapiTicket(); |     return this.configStorage.getJsapiTicket(); | ||||||
|   } |   } | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Eric.Tsai
					Eric.Tsai