Răsfoiți Sursa

feat(backend): WechatService access_token 改用 Redis 缓存,多实例共享避免重复请求微信

Xiaogang Liao 1 lună în urmă
părinte
comite
19037d530f

+ 35 - 1
cfc-backend/src/main/java/com/etotem/cfc/service/WechatService.java

@@ -13,8 +13,10 @@ import org.springframework.stereotype.Service;
 import org.springframework.web.client.RestTemplate;
 import org.springframework.util.StreamUtils;
 import com.etotem.cfc.service.api.WechatServiceInterface;
+import org.springframework.data.redis.core.RedisTemplate;
 
 import javax.annotation.PostConstruct;
+import javax.annotation.Resource;
 import javax.crypto.Cipher;
 import javax.crypto.spec.IvParameterSpec;
 import javax.crypto.spec.SecretKeySpec;
@@ -32,6 +34,7 @@ import java.util.Base64;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.UUID;
+import java.time.Duration;
 
 @Service
 public class WechatService implements WechatServiceInterface {
@@ -81,6 +84,13 @@ public class WechatService implements WechatServiceInterface {
         return new RestTemplate(factory);
     }
 
+    @Resource
+    private RedisTemplate<String, Object> redisTemplate;
+
+    /** Redis access_token 缓存 key 与 TTL(秒) */
+    private static final String STABLE_TOKEN_KEY = "wechat:stable_access_token";
+    private static final long STABLE_TOKEN_TTL_SECONDS = 7000;
+
     // ===== stable access_token 缓存(独立缓存,用于避免"not latest"冲突)=====
     private volatile String cachedStableAccessToken;
     private volatile long stableTokenExpireTime;
@@ -268,9 +278,28 @@ public class WechatService implements WechatServiceInterface {
             if (cachedStableAccessToken != null && now < stableTokenExpireTime) {
                 return cachedStableAccessToken;
             }
+            // 内存未命中:优先从 Redis 读取(多实例共享同一 token,避免重复请求微信)
+            try {
+                Object cached = redisTemplate.opsForValue().get(STABLE_TOKEN_KEY);
+                if (cached != null) {
+                    String token = cached.toString();
+                    cachedStableAccessToken = token;
+                    stableTokenExpireTime = now + STABLE_TOKEN_TTL_SECONDS * 1000;
+                    return token;
+                }
+            } catch (Exception e) {
+                log.warn("Redis 读取 access_token 失败,走微信接口: {}", e.getMessage());
+            }
             String token = doGetStableAccessToken();
             cachedStableAccessToken = token;
-            stableTokenExpireTime = now + 7000 * 1000;
+            stableTokenExpireTime = now + STABLE_TOKEN_TTL_SECONDS * 1000;
+            // 回写 Redis 供多实例共享;失败不影响本次请求
+            try {
+                redisTemplate.opsForValue().set(STABLE_TOKEN_KEY, token,
+                        Duration.ofSeconds(STABLE_TOKEN_TTL_SECONDS));
+            } catch (Exception e) {
+                log.warn("Redis 写入 access_token 失败(不影响本次请求): {}", e.getMessage());
+            }
             return token;
         }
     }
@@ -284,6 +313,11 @@ public class WechatService implements WechatServiceInterface {
     public synchronized void invalidateAccessToken() {
         cachedStableAccessToken = null;
         stableTokenExpireTime = 0;
+        try {
+            redisTemplate.delete(STABLE_TOKEN_KEY);
+        } catch (Exception e) {
+            log.warn("Redis 删除 access_token 失败(忽略): {}", e.getMessage());
+        }
     }
 
     /**