caffeine+redis做二級快取
阿新 • • 發佈:2021-06-28
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") //prod這個profile時快取才生效 @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