caffeine+redis做二级缓存
-
caffeine+redis做二级缓存
caffeine是基于Java8的本地缓存(进程内缓存)
-
pom.xml注入依赖
<!-- 注入redis依赖 --> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId> </dependency> -
application.properties配置文件
#用来控制redis是否生效 1生效 spring.redis1.enabled=1 -
CacheConfig 配置caffeine缓存的基本信息 名称、超时时长、最大容量等
import java.util.ArrayList; import java.util.concurrent.TimeUnit; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.caffeine.CaffeineCache; import org.springframework.cache.support.SimpleCacheManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Profile; import com.github.benmanes.caffeine.cache.Caffeine; //@Profile("cacheenable") //指定当前环境 不指定,任何环境下都能注册这个组件 @Configuration @EnableCaching //开启缓存 public class CacheConfig { public static final int DEFAULT_MAXSIZE = 288000; public static final int DEFAULT_TTL = 1000; private SimpleCacheManager cacheManager = new SimpleCacheManager(); // 定义cache名称、超时时长(秒)、最大容量 public enum CacheEnum { homePage(288000, 1000), // 有效期8个小时 , 最大容量1000 ; CacheEnum(int ttl, int maxSize) { this.ttl = ttl; this.maxSize = maxSize; } private int maxSize = DEFAULT_MAXSIZE; // 最大數量 private int ttl = DEFAULT_TTL; // 过期时间(秒) public int getMaxSize() { return maxSize; } public int getTtl() { return ttl; } } // 创建基于Caffeine的Cache Manager @Bean @Primary public CacheManager caffeineCacheManager() { ArrayList<CaffeineCache> caches = new ArrayList<CaffeineCache>(); // 最后一次写入或访问后经过8H过期 for (CacheEnum c : CacheEnum.values()) { caches.add(new CaffeineCache(c.name(), Caffeine.newBuilder().recordStats() .expireAfterAccess(c.getTtl(), TimeUnit.SECONDS).maximumSize(c.getMaxSize()).build())); } cacheManager.setCaches(caches); return cacheManager; } @Bean public CacheManager getCacheManager() { return cacheManager; } } -
代码
/** * value 对应的是CacheConfig中的cache名称 * sync 是否异步 * */ @Cacheable(value = "homePage", key = "'live'.concat(':').concat(#source).concat(':').concat(#channelId)", sync = true) public String makeLiveUrl(Long channelId, Integer source) { // 作成url String prefixUrl = ""; if (redis1enabled == 1) { logger.info("从redis中获取数据"); Object redisResultUrl = redisUtil.get("live:" + source + ":" + String.valueOf(channelId)); if (redisResultUrl == null) { logger.info("从数据库中获取数据"); // getUrlForDb 取数据库中的数据 prefixUrl = getUrlForDb(channelId, source, UrlTypeEnum.LIVE_TYPE.getValue()); if (prefixUrl == null) { redisUtil.set("live:" + source + ":" + String.valueOf(channelId), "-1", 0); } else { redisUtil.set("live:" + source + ":" + String.valueOf(channelId), prefixUrl, 0); } } else { if (redisResultUrl.equals("-1")) { prefixUrl = null; } else { prefixUrl = (String) redisResultUrl; } } } else { prefixUrl = getUrlForDb(channelId, source, UrlTypeEnum.LIVE_TYPE.getValue()); } return prefixUrl; }
因为 Spring Cache是基于切面的(基于AOP的动态代理实现的:即都在方法调用前后去获取方法的名称、参数、返回值,然后根据方法名称、参数生产缓存的key,进行缓存),所以内部方法调用不会调用切面,导致缓存不生效,可以写一个工具类,使用内部调用的时候,自己实例化一个对象,让类走AOP
-
-
Caffeine 获取本地所有的key
List<String> list = new ArrayList<>(); // 获取caffeine对应的缓存 Cache cache = CacheConfig.cacheManager.getCache("channel"); Object nativeCache = cache.getNativeCache(); try { @SuppressWarnings("unchecked") // map存放的是key-value Map<String, Object> map = (Map<String, Object>) ObjToMap(nativeCache).get("cache"); for (Map.Entry<String, Object> entry : map.entrySet()) { // 循环获取key list.add(entry.getKey()); } } catch (Exception e) { logger.warn("DictionaryItem缓存错误!!!"); } // caffeine缓存所有的key System.out.println(list);因为cache.getNativeCache();的返回值是object型,所有需要object转map
/** * Obj 转换为 map * * @param obj * @return * @throws Exception */ public static Map<String, Object> ObjToMap(Object obj) throws Exception { Map<String, Object> map = new HashMap<>(); Field[] fields = obj.getClass().getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); map.put(field.getName(), field.get(obj)); } return map; }

浙公网安备 33010602011771号