feat(integration): 支持TypeReference泛型的降级缓存机制

- 在IntegrationFallbackService中新增支持TypeReference的executeWithFallback方法
- 新增getFallbackFromCache和parseFallbackCacheValue方法处理泛型缓存
- 更新DeviceStatusIntegrationService使用TypeReference保留泛型信息
- 更新RenderWorkerConfigIntegrationService使用TypeReference并修正缓存键
- 更新ScenicConfigIntegrationService使用TypeReference保留泛型信息
- 添加必要的Jackson TypeReference导入依赖
This commit is contained in:
2025-12-16 10:00:49 +08:00
parent b207b5805a
commit a5903a9831
4 changed files with 101 additions and 8 deletions

View File

@@ -1,5 +1,6 @@
package com.ycwl.basic.integration.common.service; package com.ycwl.basic.integration.common.service;
import com.fasterxml.jackson.core.type.TypeReference;
import com.ycwl.basic.integration.common.config.IntegrationProperties; import com.ycwl.basic.integration.common.config.IntegrationProperties;
import com.ycwl.basic.utils.JacksonUtil; import com.ycwl.basic.utils.JacksonUtil;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@@ -30,7 +31,7 @@ public class IntegrationFallbackService {
/** /**
* 执行操作,失败时降级到缓存结果 * 执行操作,失败时降级到缓存结果
* *
* @param serviceName 服务名称 (如: zt-device, zt-scenic) * @param serviceName 服务名称 (如: zt-device, zt-scenic)
* @param cacheKey 缓存键 * @param cacheKey 缓存键
* @param operation 主要操作 * @param operation 主要操作
@@ -78,6 +79,57 @@ public class IntegrationFallbackService {
return fallbackResult; return fallbackResult;
} }
} }
/**
* 执行操作,失败时降级到缓存结果(支持TypeReference泛型)
*
* @param serviceName 服务名称 (如: zt-device, zt-scenic)
* @param cacheKey 缓存键
* @param operation 主要操作
* @param typeReference 类型引用,用于保留泛型信息
* @param <T> 结果类型
* @return 操作结果或缓存的结果
*/
public <T> T executeWithFallback(String serviceName, String cacheKey, Supplier<T> operation, TypeReference<T> typeReference) {
String fullKey = buildFullCacheKey(serviceName, cacheKey);
String cachedValue = null;
boolean isPreferredCache = false;
try {
cachedValue = redisTemplate.opsForValue().get(fullKey);
isPreferredCache = cachedValue != null && isFallbackCachePreferred(serviceName, fullKey);
} catch (Exception e) {
log.warn("[{}] 读取降级缓存失败,将继续尝试远端获取, cacheKey: {}", serviceName, cacheKey, e);
}
if (isPreferredCache) {
T preferredCacheResult = parseFallbackCacheValue(serviceName, cacheKey, cachedValue, typeReference);
if (preferredCacheResult != null) {
log.debug("[{}] 命中优先缓存(<=1分钟),直接返回, cacheKey: {}", serviceName, cacheKey);
return preferredCacheResult;
}
}
try {
T result = operation.get();
if (result != null) {
// 操作成功,保存结果用于将来的降级
storeFallbackCache(serviceName, cacheKey, result);
}
return result;
} catch (Exception e) {
log.warn("[{}] 操作失败,尝试降级到缓存结果, cacheKey: {}", serviceName, cacheKey, e);
T fallbackResult = parseFallbackCacheValue(serviceName, cacheKey, cachedValue, typeReference);
if (fallbackResult == null) {
fallbackResult = getFallbackFromCache(serviceName, cacheKey, typeReference);
}
if (fallbackResult == null) {
log.error("[{}] 操作失败且无缓存数据, cacheKey: {}", serviceName, cacheKey);
throw e;
}
log.info("[{}] 成功从降级缓存获取结果, cacheKey: {}", serviceName, cacheKey);
return fallbackResult;
}
}
/** /**
* 执行操作,失败时降级到缓存结果,无返回值版本 * 执行操作,失败时降级到缓存结果,无返回值版本
@@ -138,6 +190,23 @@ public class IntegrationFallbackService {
return null; return null;
} }
/**
* 从降级缓存获取结果(支持TypeReference泛型)
*/
private <T> T getFallbackFromCache(String serviceName, String cacheKey, TypeReference<T> typeReference) {
try {
String fullKey = buildFullCacheKey(serviceName, cacheKey);
String cachedValue = redisTemplate.opsForValue().get(fullKey);
if (cachedValue != null) {
log.debug("[{}] 从降级缓存获取结果, key: {}", serviceName, fullKey);
return JacksonUtil.parseObject(cachedValue, typeReference);
}
} catch (Exception e) {
log.warn("[{}] 从降级缓存获取结果失败, cacheKey: {}", serviceName, cacheKey, e);
}
return null;
}
/** /**
* 判断当前降级缓存是否应该优先使用。 * 判断当前降级缓存是否应该优先使用。
* 规则:缓存写入后的 1 分钟内优先使用,超过 1 分钟则优先尝试远端;远端失败再降级到缓存。 * 规则:缓存写入后的 1 分钟内优先使用,超过 1 分钟则优先尝试远端;远端失败再降级到缓存。
@@ -177,6 +246,21 @@ public class IntegrationFallbackService {
return null; return null;
} }
} }
/**
* 解析降级缓存值(支持TypeReference泛型)
*/
private <T> T parseFallbackCacheValue(String serviceName, String cacheKey, String cachedValue, TypeReference<T> typeReference) {
if (cachedValue == null) {
return null;
}
try {
return JacksonUtil.parseObject(cachedValue, typeReference);
} catch (Exception e) {
log.warn("[{}] 解析降级缓存失败, cacheKey: {}", serviceName, cacheKey, e);
return null;
}
}
/** /**
* 清除降级缓存 * 清除降级缓存

View File

@@ -1,5 +1,6 @@
package com.ycwl.basic.integration.device.service; package com.ycwl.basic.integration.device.service;
import com.fasterxml.jackson.core.type.TypeReference;
import com.ycwl.basic.integration.common.exception.IntegrationException; import com.ycwl.basic.integration.common.exception.IntegrationException;
import com.ycwl.basic.integration.common.response.CommonResponse; import com.ycwl.basic.integration.common.response.CommonResponse;
import com.ycwl.basic.integration.common.service.IntegrationFallbackService; import com.ycwl.basic.integration.common.service.IntegrationFallbackService;
@@ -49,6 +50,9 @@ public class DeviceStatusIntegrationService {
); );
} }
/**
* 获取所有在线设备(带降级,使用TypeReference保留泛型信息)
*/
public List<DeviceStatusDTO> getAllOnlineDevices() { public List<DeviceStatusDTO> getAllOnlineDevices() {
log.debug("获取所有在线设备"); log.debug("获取所有在线设备");
return fallbackService.executeWithFallback( return fallbackService.executeWithFallback(
@@ -58,7 +62,7 @@ public class DeviceStatusIntegrationService {
CommonResponse<List<DeviceStatusDTO>> response = deviceStatusClient.getAllOnlineDevices(); CommonResponse<List<DeviceStatusDTO>> response = deviceStatusClient.getAllOnlineDevices();
return handleResponse(response, "获取所有在线设备失败"); return handleResponse(response, "获取所有在线设备失败");
}, },
List.class new TypeReference<List<DeviceStatusDTO>>() {}
); );
} }

View File

@@ -1,5 +1,6 @@
package com.ycwl.basic.integration.render.service; package com.ycwl.basic.integration.render.service;
import com.fasterxml.jackson.core.type.TypeReference;
import com.ycwl.basic.integration.common.exception.IntegrationException; import com.ycwl.basic.integration.common.exception.IntegrationException;
import com.ycwl.basic.integration.common.response.CommonResponse; import com.ycwl.basic.integration.common.response.CommonResponse;
import com.ycwl.basic.integration.common.service.IntegrationFallbackService; import com.ycwl.basic.integration.common.service.IntegrationFallbackService;
@@ -29,7 +30,7 @@ public class RenderWorkerConfigIntegrationService {
private static final String SERVICE_NAME = "zt-render-worker"; private static final String SERVICE_NAME = "zt-render-worker";
/** /**
* 获取工作器所有配置(带降级) * 获取工作器所有配置(带降级,使用TypeReference保留泛型信息
*/ */
public List<RenderWorkerConfigV2DTO> getWorkerConfigs(Long workerId) { public List<RenderWorkerConfigV2DTO> getWorkerConfigs(Long workerId) {
log.debug("获取渲染工作器配置列表, workerId: {}", workerId); log.debug("获取渲染工作器配置列表, workerId: {}", workerId);
@@ -37,12 +38,12 @@ public class RenderWorkerConfigIntegrationService {
SERVICE_NAME, SERVICE_NAME,
"worker:configs:" + workerId, "worker:configs:" + workerId,
() -> { () -> {
CommonResponse<List<RenderWorkerConfigV2DTO>> response = CommonResponse<List<RenderWorkerConfigV2DTO>> response =
renderWorkerConfigV2Client.getWorkerConfigs(workerId); renderWorkerConfigV2Client.getWorkerConfigs(workerId);
List<RenderWorkerConfigV2DTO> configs = handleResponse(response, "获取渲染工作器配置列表失败"); List<RenderWorkerConfigV2DTO> configs = handleResponse(response, "获取渲染工作器配置列表失败");
return configs != null ? configs : Collections.emptyList(); return configs != null ? configs : Collections.emptyList();
}, },
List.class new TypeReference<List<RenderWorkerConfigV2DTO>>() {}
); );
} }
@@ -70,12 +71,12 @@ public class RenderWorkerConfigIntegrationService {
log.debug("获取渲染工作器平铺配置, workerId: {}", workerId); log.debug("获取渲染工作器平铺配置, workerId: {}", workerId);
return fallbackService.executeWithFallback( return fallbackService.executeWithFallback(
SERVICE_NAME, SERVICE_NAME,
"worker:config:" + workerId, "worker:flat:config:" + workerId,
() -> { () -> {
List<RenderWorkerConfigV2DTO> configs = getWorkerConfigsInternal(workerId); List<RenderWorkerConfigV2DTO> configs = getWorkerConfigsInternal(workerId);
return flattenConfigs(configs); return flattenConfigs(configs);
}, },
Map.class new TypeReference<Map<String, Object>>() {}
); );
} }

View File

@@ -1,5 +1,6 @@
package com.ycwl.basic.integration.scenic.service; package com.ycwl.basic.integration.scenic.service;
import com.fasterxml.jackson.core.type.TypeReference;
import com.ycwl.basic.integration.common.exception.IntegrationException; import com.ycwl.basic.integration.common.exception.IntegrationException;
import com.ycwl.basic.integration.common.response.CommonResponse; import com.ycwl.basic.integration.common.response.CommonResponse;
import com.ycwl.basic.integration.common.service.IntegrationFallbackService; import com.ycwl.basic.integration.common.service.IntegrationFallbackService;
@@ -22,6 +23,9 @@ public class ScenicConfigIntegrationService {
private static final String SERVICE_NAME = "zt-scenic"; private static final String SERVICE_NAME = "zt-scenic";
/**
* 获取景区配置列表(带降级,使用TypeReference保留泛型信息)
*/
public List<ScenicConfigV2DTO> listConfigs(Long scenicId) { public List<ScenicConfigV2DTO> listConfigs(Long scenicId) {
log.debug("获取景区配置列表, scenicId: {}", scenicId); log.debug("获取景区配置列表, scenicId: {}", scenicId);
return fallbackService.executeWithFallback( return fallbackService.executeWithFallback(
@@ -31,7 +35,7 @@ public class ScenicConfigIntegrationService {
CommonResponse<List<ScenicConfigV2DTO>> response = scenicConfigV2Client.listConfigs(scenicId); CommonResponse<List<ScenicConfigV2DTO>> response = scenicConfigV2Client.listConfigs(scenicId);
return handleResponse(response, "获取景区配置列表失败"); return handleResponse(response, "获取景区配置列表失败");
}, },
List.class new TypeReference<List<ScenicConfigV2DTO>>() {}
); );
} }