guava本地缓存+函数式编程
【摘要】 1.引入依赖 1.sun-dependencies <guava.version>19.0</guava.version> <fastjson.version>1.2.83</fastjson.version> <!-- guava本地缓存 --> <dependency> ...
1.引入依赖
1.sun-dependencies
<guava.version>19.0</guava.version>
<fastjson.version>1.2.83</fastjson.version>
<!-- guava本地缓存 -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<!-- fastjson序列化 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
2.sun-common-redis
<!-- guava本地缓存 -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<!-- fastjson序列化 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
2.CacheUtil.java封装和使用
1.CacheUtil.java
package com.sunxiansheng.redis.util;
import com.alibaba.fastjson.JSON;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
/**
* Description: Guava本地缓存工具类
* @Author sun
* @Create 2024/7/22 12:55
* @Version 1.0
*/
@Component
@Slf4j
public class CacheUtil<K, V> {
// 读取配置文件,支持动态刷新(需要配置Nacos)
@Value("${guaca.cache.switch:false}")
private Boolean cacheEnabled;
@Value("${guaca.cache.maximumSize:5000}")
private int maximumSize;
@Value("${guaca.cache.expireAfterAccess:3}")
private int expireAfterAccess;
/**
* 缓存key连接符
*/
private static final String CACHE_KEY_SEPARATOR = "_";
// 初始化一个Guava缓存
private final Cache<String, String> localCache = CacheBuilder.newBuilder()
.maximumSize(maximumSize)
.expireAfterAccess(expireAfterAccess, TimeUnit.SECONDS)
.build();
/**
* 使用本地缓存获取结果(批量)
*
* @param skuIdList id列表
* @param cachePrefix 查询的前缀(缓存的key由前缀 + "_" + id构成)
* @param clazz 查询完结果后要反序列化的类型
* @param function 不走缓存查询结果的逻辑
* @return 查询结果的Map
*/
public Map<K, V> getResult(List<K> skuIdList, String cachePrefix, Class<V> clazz, Function<List<K>, Map<K, V>> function) {
// 判空
if (CollectionUtils.isEmpty(skuIdList)) {
return Collections.emptyMap();
}
Map<K, V> resultMap = new HashMap<>(16);
// 如果缓存开关未开启,直接使用function查询
if (Boolean.FALSE.equals(cacheEnabled)) {
return function.apply(skuIdList);
}
// 记录未命中缓存的ID
List<K> noCacheIdList = new LinkedList<>();
// 查Guava本地缓存
for (K skuId : skuIdList) {
String cacheKey = generateCacheKey(cachePrefix, skuId);
String content = localCache.getIfPresent(cacheKey);
if (StringUtils.isNotBlank(content)) {
V v = JSON.parseObject(content, clazz);
resultMap.put(skuId, v);
} else {
noCacheIdList.add(skuId);
}
}
// 记录未命中缓存的日志
if (!CollectionUtils.isEmpty(noCacheIdList)) {
log.debug("Cache miss for keys: {}", noCacheIdList);
}
// 如果所有ID都命中缓存,直接返回结果
if (CollectionUtils.isEmpty(noCacheIdList)) {
return resultMap;
}
// 使用function查询未命中缓存的ID
Map<K, V> noCacheResultMap = function.apply(noCacheIdList);
if (!CollectionUtils.isEmpty(noCacheResultMap)) {
for (Map.Entry<K, V> entry : noCacheResultMap.entrySet()) {
K skuId = entry.getKey();
V content = entry.getValue();
resultMap.put(skuId, content);
String cacheKey = generateCacheKey(cachePrefix, skuId);
localCache.put(cacheKey, JSON.toJSONString(content));
}
}
return resultMap;
}
/**
* 使用本地缓存获取单个结果
*
* @param key 缓存的键
* @param cachePrefix 查询的前缀(缓存的key由前缀 + "_" + key构成)
* @param clazz 查询完结果后要反序列化的类型
* @param function 不走缓存查询结果的逻辑
* @return 查询结果
* @throws ExecutionException
*/
public V getSingleResult(K key, String cachePrefix, Class<V> clazz, Function<K, V> function) throws ExecutionException {
String cacheKey = generateCacheKey(cachePrefix, key);
String content = localCache.getIfPresent(cacheKey);
if (StringUtils.isNotBlank(content)) {
return JSON.parseObject(content, clazz);
}
V result = function.apply(key);
if (result != null) {
localCache.put(cacheKey, JSON.toJSONString(result));
}
return result;
}
/**
* 清除单个缓存
*
* @param key 缓存的键
* @param cachePrefix 查询的前缀(缓存的key由前缀 + "_" + key构成)
*/
public void invalidateSingleCache(K key, String cachePrefix) {
String cacheKey = generateCacheKey(cachePrefix, key);
localCache.invalidate(cacheKey);
log.debug("Cache invalidated for key: {}", cacheKey);
}
/**
* 清除多个缓存
*
* @param keys 缓存的键列表
* @param cachePrefix 查询的前缀(缓存的key由前缀 + "_" + key构成)
*/
public void invalidateMultipleCaches(List<K> keys, String cachePrefix) {
List<String> cacheKeys = new ArrayList<>();
for (K key : keys) {
String cacheKey = generateCacheKey(cachePrefix, key);
cacheKeys.add(cacheKey);
log.debug("Cache invalidated for key: {}", cacheKey);
}
localCache.invalidateAll(cacheKeys);
}
/**
* 清除所有缓存
*/
public void invalidateAllCaches() {
localCache.invalidateAll();
log.debug("All caches invalidated.");
}
/**
* 生成缓存键
*
* @param prefix 缓存前缀
* @param id 缓存ID
* @return 缓存键
*/
private String generateCacheKey(String prefix, K id) {
return prefix + CACHE_KEY_SEPARATOR + id;
}
}
2.使用方式
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
@Service
public class CacheService {
@Autowired
private CacheUtil<String, String> cacheUtil;
/**
* 查询批量数据
* @param ids 数据ID列表
* @return 查询结果的Map
*/
public Map<String, String> queryData(List<String> ids) {
// 调用cacheUtil获取数据
return cacheUtil.getResult(ids, "dataPrefix", String.class, this::loadFromDatabase);
}
/**
* 查询单个数据
* @param id 数据ID
* @return 查询结果
* @throws ExecutionException
*/
public String querySingleData(String id) throws ExecutionException {
// 调用cacheUtil获取单个数据
return cacheUtil.getSingleResult(id, "dataPrefix", String.class, this::loadSingleFromDatabase);
}
/**
* 更新数据并清除相关缓存
* @param id 数据ID
* @param newValue 新的数据值
*/
public void updateData(String id, String newValue) {
// 更新数据到数据库
saveToDatabase(id, newValue);
// 清除单个缓存
cacheUtil.invalidateSingleCache(id, "dataPrefix");
}
/**
* 批量更新数据并清除相关缓存
* @param dataMap 数据Map
*/
public void updateMultipleData(Map<String, String> dataMap) {
// 更新数据到数据库
saveMultipleToDatabase(dataMap);
// 清除多个缓存
cacheUtil.invalidateMultipleCaches(new ArrayList<>(dataMap.keySet()), "dataPrefix");
}
/**
* 清除所有缓存
*/
public void clearAllCaches() {
cacheUtil.invalidateAllCaches();
}
// 模拟从数据库加载批量数据
private Map<String, String> loadFromDatabase(List<String> ids) {
// 实际实现时应从数据库或其他数据源加载数据
// 这里简单模拟返回
return Map.of("id1", "Value for id1", "id2", "Value for id2", "id3", "Value for id3");
}
// 模拟从数据库加载单个数据
private String loadSingleFromDatabase(String id) {
// 实际实现时应从数据库或其他数据源加载数据
// 这里简单模拟返回
return "Value for " + id;
}
// 模拟保存单个数据到数据库
private void saveToDatabase(String id, String value) {
// 实际实现时应保存到数据库或其他数据源
// 这里简单模拟
System.out.println("Saved " + value + " for " + id + " to database");
}
// 模拟保存多个数据到数据库
private void saveMultipleToDatabase(Map<String, String> dataMap) {
// 实际实现时应保存到数据库或其他数据源
// 这里简单模拟
dataMap.forEach((id, value) -> System.out.println("Saved " + value + " for " + id + " to database"));
}
}
【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
作者其他文章
评论(0)