feat(service): 使用带TTL的缓存Map替换静态Map

- 新增TtlCacheMap类,用于实现带生存时间的缓存
- 在ScenicServiceImpl中使用TtlCacheMap替换原有的ConcurrentHashMap
- 为不同类型的适配器创建了对应的缓存Map
- 优化了缓存获取逻辑,增加了TTL支持
- 添加了缓存清理和统计功能
This commit is contained in:
2025-08-28 16:02:30 +08:00
parent 46fb255e66
commit 798ff3b9b5
2 changed files with 452 additions and 11 deletions

View File

@@ -13,6 +13,7 @@ import com.ycwl.basic.storage.StorageFactory;
import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.storage.exceptions.StorageUnsupportedException;
import com.ycwl.basic.util.ScenicConfigManager;
import com.ycwl.basic.util.TtlCacheMap;
import com.ycwl.basic.utils.ApiResponse;
import com.ycwl.basic.utils.JacksonUtil;
import lombok.extern.slf4j.Slf4j;
@@ -21,7 +22,7 @@ import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
/**
* @Author:longbinbin
@@ -32,6 +33,21 @@ import java.util.concurrent.ConcurrentHashMap;
public class ScenicServiceImpl implements ScenicService {
@Autowired
private ScenicRepository scenicRepository;
// TTL缓存配置,默认10分钟过期
private static final long DEFAULT_CACHE_TTL_MINUTES = 10;
// 使用TTL缓存替代静态Map
private static final TtlCacheMap<Long, IStorageAdapter> scenicStorageAdapterCache =
new TtlCacheMap<>(TimeUnit.MINUTES.toMillis(DEFAULT_CACHE_TTL_MINUTES));
private static final TtlCacheMap<Long, IStorageAdapter> scenicTmpStorageAdapterCache =
new TtlCacheMap<>(TimeUnit.MINUTES.toMillis(DEFAULT_CACHE_TTL_MINUTES));
private static final TtlCacheMap<Long, IStorageAdapter> scenicLocalStorageAdapterCache =
new TtlCacheMap<>(TimeUnit.MINUTES.toMillis(DEFAULT_CACHE_TTL_MINUTES));
private static final TtlCacheMap<Long, IFaceBodyAdapter> scenicFaceBodyAdapterCache =
new TtlCacheMap<>(TimeUnit.MINUTES.toMillis(DEFAULT_CACHE_TTL_MINUTES));
private static final TtlCacheMap<Long, IPayAdapter> scenicPayAdapterCache =
new TtlCacheMap<>(TimeUnit.MINUTES.toMillis(DEFAULT_CACHE_TTL_MINUTES));
@Override
@Deprecated
@@ -39,10 +55,9 @@ public class ScenicServiceImpl implements ScenicService {
return ApiResponse.success(scenicRepository.list(scenicReqQuery));
}
private static final Map<Long, IStorageAdapter> scenicStorageAdapterMap = new ConcurrentHashMap<>();
@Override
public IStorageAdapter getScenicStorageAdapter(Long scenicId) {
return scenicStorageAdapterMap.computeIfAbsent(scenicId, (key) -> {
return scenicStorageAdapterCache.computeIfAbsent(scenicId, (key) -> {
IStorageAdapter adapter;
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId);
if (scenicConfig.getString("store_type") != null) {
@@ -58,10 +73,9 @@ public class ScenicServiceImpl implements ScenicService {
return adapter;
});
}
private static final Map<Long, IStorageAdapter> scenicTmpStorageAdapterMap = new ConcurrentHashMap<>();
@Override
public IStorageAdapter getScenicTmpStorageAdapter(Long scenicId) {
return scenicTmpStorageAdapterMap.computeIfAbsent(scenicId, (key) -> {
return scenicTmpStorageAdapterCache.computeIfAbsent(scenicId, (key) -> {
IStorageAdapter adapter;
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId);
if (scenicConfig.getString("tmp_store_type") != null) {
@@ -77,10 +91,9 @@ public class ScenicServiceImpl implements ScenicService {
return adapter;
});
}
private static final Map<Long, IStorageAdapter> scenicLocalStorageAdapterMap = new ConcurrentHashMap<>();
@Override
public IStorageAdapter getScenicLocalStorageAdapter(Long scenicId) {
return scenicLocalStorageAdapterMap.computeIfAbsent(scenicId, (key) -> {
return scenicLocalStorageAdapterCache.computeIfAbsent(scenicId, (key) -> {
IStorageAdapter adapter;
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId);
if (scenicConfig.getString("local_store_type") != null) {
@@ -97,10 +110,9 @@ public class ScenicServiceImpl implements ScenicService {
});
}
private static final Map<Long, IFaceBodyAdapter> scenicFaceBodyAdapterMap = new ConcurrentHashMap<>();
@Override
public IFaceBodyAdapter getScenicFaceBodyAdapter(Long scenicId) {
return scenicFaceBodyAdapterMap.computeIfAbsent(scenicId, (key) -> {
return scenicFaceBodyAdapterCache.computeIfAbsent(scenicId, (key) -> {
IFaceBodyAdapter adapter;
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId);
if (scenicConfig.getString("face_type") != null) {
@@ -113,10 +125,9 @@ public class ScenicServiceImpl implements ScenicService {
});
}
private static final Map<Long, IPayAdapter> scenicPayAdapterMap = new ConcurrentHashMap<>();
@Override
public IPayAdapter getScenicPayAdapter(Long scenicId) {
return scenicPayAdapterMap.computeIfAbsent(scenicId, (key) -> {
return scenicPayAdapterCache.computeIfAbsent(scenicId, (key) -> {
IPayAdapter adapter;
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId);
if (scenicConfig.getString("pay_type") != null) {
@@ -128,4 +139,94 @@ public class ScenicServiceImpl implements ScenicService {
return adapter;
});
}
// ==================== 缓存管理方法 ====================
/**
* 清除指定景区的所有适配器缓存
*
* @param scenicId 景区ID
*/
public void clearScenicAdapterCache(Long scenicId) {
log.info("清除景区 {} 的所有适配器缓存", scenicId);
scenicStorageAdapterCache.remove(scenicId);
scenicTmpStorageAdapterCache.remove(scenicId);
scenicLocalStorageAdapterCache.remove(scenicId);
scenicFaceBodyAdapterCache.remove(scenicId);
scenicPayAdapterCache.remove(scenicId);
}
/**
* 清除所有适配器缓存
*/
public void clearAllAdapterCache() {
log.info("清除所有适配器缓存");
scenicStorageAdapterCache.clear();
scenicTmpStorageAdapterCache.clear();
scenicLocalStorageAdapterCache.clear();
scenicFaceBodyAdapterCache.clear();
scenicPayAdapterCache.clear();
}
/**
* 手动触发过期缓存清理
*
* @return 清理的过期缓存项总数
*/
public int cleanupExpiredCache() {
log.info("手动触发过期缓存清理");
int totalCleaned = 0;
totalCleaned += scenicStorageAdapterCache.cleanupExpired();
totalCleaned += scenicTmpStorageAdapterCache.cleanupExpired();
totalCleaned += scenicLocalStorageAdapterCache.cleanupExpired();
totalCleaned += scenicFaceBodyAdapterCache.cleanupExpired();
totalCleaned += scenicPayAdapterCache.cleanupExpired();
log.info("清理了 {} 个过期缓存项", totalCleaned);
return totalCleaned;
}
/**
* 获取缓存统计信息
*
* @return 缓存统计信息
*/
public String getCacheStats() {
StringBuilder stats = new StringBuilder();
stats.append("=== ScenicServiceImpl 缓存统计信息 ===\n");
stats.append("Storage Adapter Cache: ").append(scenicStorageAdapterCache.getStats()).append("\n");
stats.append("Tmp Storage Adapter Cache: ").append(scenicTmpStorageAdapterCache.getStats()).append("\n");
stats.append("Local Storage Adapter Cache: ").append(scenicLocalStorageAdapterCache.getStats()).append("\n");
stats.append("FaceBody Adapter Cache: ").append(scenicFaceBodyAdapterCache.getStats()).append("\n");
stats.append("Pay Adapter Cache: ").append(scenicPayAdapterCache.getStats()).append("\n");
return stats.toString();
}
/**
* 重置所有缓存统计信息
*/
public void resetCacheStats() {
log.info("重置所有缓存统计信息");
scenicStorageAdapterCache.resetStats();
scenicTmpStorageAdapterCache.resetStats();
scenicLocalStorageAdapterCache.resetStats();
scenicFaceBodyAdapterCache.resetStats();
scenicPayAdapterCache.resetStats();
}
/**
* 获取指定景区缓存的剩余TTL时间
*
* @param scenicId 景区ID
* @return 各类型适配器缓存的剩余TTL时间(毫秒)
*/
public String getScenicCacheTtl(Long scenicId) {
StringBuilder ttlInfo = new StringBuilder();
ttlInfo.append("景区 ").append(scenicId).append(" 缓存TTL信息:\n");
ttlInfo.append("Storage: ").append(scenicStorageAdapterCache.getRemainTtl(scenicId)).append("ms\n");
ttlInfo.append("TmpStorage: ").append(scenicTmpStorageAdapterCache.getRemainTtl(scenicId)).append("ms\n");
ttlInfo.append("LocalStorage: ").append(scenicLocalStorageAdapterCache.getRemainTtl(scenicId)).append("ms\n");
ttlInfo.append("FaceBody: ").append(scenicFaceBodyAdapterCache.getRemainTtl(scenicId)).append("ms\n");
ttlInfo.append("Pay: ").append(scenicPayAdapterCache.getRemainTtl(scenicId)).append("ms\n");
return ttlInfo.toString();
}
}