目录
Caffeine工具类方式
SpringBoot 整合 Caffeine 缓存 (SpringCache模式)
驱逐策略
开发使用
Caffeine是一种高性能的缓存库,是基于Java 8的最佳(最优)缓存框架,性能各方面优于guava。
Caffeine工具类方式
原文链接:https://www.cnblogs.com/wudiffs/p/11585757.html
代码仓库如下:
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>2.4.0</version>
</dependency>
代码详细示例如下:
public class CaffeineCacheManagerService {
private static LoadingCache<String, CacheVO> cache;
private static AsyncLoadingCache<String, CacheVO> asyncCache;
private static AsyncLoadingCache<String, CacheVO> asyncCache1;
private static ExecutorService executorService = new ThreadPoolExecutor(8, 8, 8, TimeUnit.SECONDS, new
LinkedBlockingQueue<Runnable>(1204));
static {
cache = Caffeine.newBuilder()
// 初始化缓存长度
.initialCapacity(1024 * 10)
// 最大长度
.maximumSize(1024 * 10)
// 更新策略
.refreshAfterWrite(10, TimeUnit.SECONDS)
// 设置缓存的过期时间
.expireAfterWrite(10, TimeUnit.SECONDS)
.build(new CacheLoader<String, CacheVO>() {
// 同步加载
@CheckForNull
@Override
public CacheVO load(@Nonnull String key) throws Exception {
return createCacheVO(key);
}
// getAll将会对缓存中没有值的key分别调用CacheLoader.load方法来构建缓存的值。
// 我们可以重写CacheLoader.loadAll方法来提高getAll的效率。
@Nonnull
@Override
public Map<String, CacheVO> loadAll(@Nonnull Iterable<? extends String> keys) throws Exception {
return createBatchCacheVOs(keys);
}
});
// 异步加载 同步load写法,最后也会转异步
asyncCache = Caffeine.newBuilder()
.maximumSize(1024 * 10)
.expireAfterWrite(10, TimeUnit.SECONDS)
.buildAsync(new CacheLoader<String, CacheVO>() {
@CheckForNull
@Override
public CacheVO load(@Nonnull String key) throws Exception {
return createCacheVO(key);
}
@Nonnull
@Override
public Map<String, CacheVO> loadAll(@Nonnull Iterable<? extends String> keys) {
return createBatchCacheVOs(keys);
}
});
// 异步加载 异步load写法
asyncCache1 = Caffeine.newBuilder()
.maximumSize(1024 * 10)
.expireAfterWrite(10, TimeUnit.SECONDS)
.buildAsync(new AsyncCacheLoader<String, CacheVO>() {
@Nonnull
@Override
public CompletableFuture<CacheVO> asyncLoad(@Nonnull String key, @Nonnull Executor executor) {
return asyncCreateCacheVO(key, executor);
}
@Nonnull
@Override
public CompletableFuture<Map<String, CacheVO>> asyncLoadAll(@Nonnull Iterable<? extends String> keys, @Nonnull Executor executor) {
return asyncCreateBatchCacheVOs(keys, executor);
}
});
}
public static CompletableFuture<CacheVO> asyncCreateCacheVO(String key, Executor executor) {
return CompletableFuture.supplyAsync(() -> createCacheVO(key), executor);
}
public static CompletableFuture<Map<String, CacheVO>> asyncCreateBatchCacheVOs(Iterable<? extends String> keys, Executor executor) {
return CompletableFuture.supplyAsync(() -> createBatchCacheVOs(keys), executor);
}
public static CacheVO createCacheVO(String key) {
return new CacheVO(key);
}
public static Map<String, CacheVO> createBatchCacheVOs(Iterable<? extends String> keys) {
Map<String, CacheVO> result = new HashMap<>();
for (String key : keys) {
result.put(key, new CacheVO(key));
}
return result;
}
public static void main(String[] args) throws Exception {
CacheVO cacheVO1 = cache.get("AA");
List<String> list = new ArrayList<>();
list.add("BB");
list.add("CC");
Map<String, CacheVO> map = cache.getAll(list);
// 如果有缓存则返回;否则运算、缓存、然后返回,整个过程是阻塞的
// 即使多个线程同时请求该值也只会调用一次Function方法
CacheVO cacheVO2 = cache.get("DD", (k) -> createCacheVO(k));
System.out.println(JSON.toJSONString(cacheVO2));
// 单个清除
cache.invalidate("AA");
// 批量清除
cache.invalidateAll(list);
// 全部清除
cache.invalidateAll();
// 返回一个CompletableFuture
CompletableFuture<CacheVO> future = asyncCache.get("EE");
CacheVO asyncCacheVO = future.get();
System.out.println(JSON.toJSONString(asyncCacheVO));
// 返回一个CompletableFuture<MAP<>>
CompletableFuture<Map<String, CacheVO>> allFuture = asyncCache.getAll(list);
Map<String, CacheVO> asyncMap = allFuture.get();
System.out.println(JSON.toJSONString(asyncMap));
CompletableFuture<CacheVO> future1 = asyncCache1.get("FF");
CacheVO asyncCacheVO1 = future1.get();
System.out.println(JSON.toJSONString(asyncCacheVO1));
CompletableFuture<Map<String, CacheVO>> allFuture1 = asyncCache1.getAll(list);
Map<String, CacheVO> asyncMap1 = allFuture.get();
System.out.println(JSON.toJSONString(asyncMap1));
}
}
或者使用下发方式实现Caffeine 工具类
支持同步、异步读写缓存实现
import com.github.benmanes.caffeine.cache.AsyncCache;
import com.github.benmanes.caffeine.cache.Caffeine;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
public class CaffeineCacheUtils {
private static com.github.benmanes.caffeine.cache.Cache<Object, Object> syncCache;
private static AsyncCache<Object, Object> asyncCache;
private CaffeineCacheUtils() {
}
public static void initCache() {
syncCache = Caffeine.newBuilder()
.initialCapacity(100)
.maximumSize(1000)
.expireAfterWrite(30, TimeUnit.MINUTES)
.build();
asyncCache = Caffeine.newBuilder()
.initialCapacity(100)
.maximumSize(1000)
.expireAfterWrite(30, TimeUnit.MINUTES)
.buildAsync();
}
public static void putSync(Object key, Object value) {
syncCache.put(key, value);
}
public static Object getSync(Object key) {
return syncCache.getIfPresent(key);
}
public static CompletableFuture<Object> getAsync(Object key, Executor executor) {
return asyncCache.get(key, k -> CompletableFuture.supplyAsync(() -> fetchDataFromDataSource(k), executor));
}
public static CompletableFuture<Void> putAsync(Object key, Object value, Executor executor) {
return asyncCache.put(key, CompletableFuture.completedFuture(value), executor);
}
public static void removeSync(Object key) {
syncCache.invalidate(key);
}
public static void clearSync() {
syncCache.invalidateAll();
}
private static Object fetchDataFromDataSource(Object key) {
// 模拟从数据源获取数据的操作
// 这里可以根据具体业务需求进行实现
return null;
}
}
SpringBoot 整合 Caffeine 缓存 (SpringCache模式)
原文链接:https://blog.csdn.net/Listening_Wind/article/details/110085228
添加依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>2.6.2</version>
</dependency>
缓存配置:
如果使用了多个cahce,比如redis、caffeine等,必须指定某一个CacheManage为@primary
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.assertj.core.util.Lists;
import org.springframework.cache.CacheManager;
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 java.util.ArrayList;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
/**
* @Author: Wxy
* @Date: 2020/11/7 16:56
* @Description
*/
@Configuration
@EnableCaching // 开启缓存,否则无效
public class CaffeineConfig {
/**
* 创建基于Caffeine的Cache Manager
*
* @return
*/
@Bean
@Primary
public CacheManager caffeineCacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
ArrayList<CaffeineCache> caches = Lists.newArrayList();
Map<String, Object> map = getCacheType();
for (String name : map.keySet()) {
caches.add(new CaffeineCache(name, (Cache<Object, Object>) map.get(name)));
}
cacheManager.setCaches(caches);
return cacheManager;
}
/**
* 初始化自定义缓存策略
*
* @return
*/
private static Map<String, Object> getCacheType() {
Map<String, Object> map = new ConcurrentHashMap<>();
map.put("name1", Caffeine.newBuilder().recordStats()
.expireAfterWrite(10, TimeUnit.SECONDS)
.maximumSize(100)
.build());
map.put("name2", Caffeine.newBuilder().recordStats()
.expireAfterWrite(50, TimeUnit.SECONDS)
.maximumSize(50)
.build());
return map;
}
}
驱逐策略
基于大小的回收策略有两种方式:基于缓存大小,基于权重,基于时间。
maximumSize : 根据缓存的计数进行驱逐 同一缓存策略 缓存的数据量,以访问先后顺序,以最大100为例,超出100驱逐最晚访问的数据缓存。
maximumWeight : 根据缓存的权重来进行驱逐(权重只是用于确定缓存大小,不会用于决定该缓存是否被驱逐)。
maximumWeight与maximumSize不可以同时使用。
Caffeine提供了三种定时驱逐策略:
expireAfterAccess(long, TimeUnit):在最后一次访问或者写入后开始计时,在指定的时间后过期。假如一直有请求访问该key,那么这个缓存将一直不会过期。
expireAfterWrite(long, TimeUnit): 在最后一次写入缓存后开始计时,在指定的时间后过期。
expireAfter(Expiry): 自定义策略,过期时间由Expiry实现独自计算。
缓存的删除策略使用的是惰性删除和定时删除。这两个删除策略的时间复杂度都是O(1)
开发使用
主要基于Spring缓存注解@Cacheable、@CacheEvict、@CachePut的方式使用
- @Cacheable :改注解修饰的方法,若不存在缓存,则执行方法并将结果写入缓存;若存在缓存,则不执行方法,直接返回缓存结果。
- @CachePut :执行方法,更新缓存;该注解下的方法始终会被执行。
- @CacheEvict :删除缓存
- @Caching 将多个缓存组合在一个方法上(该注解可以允许一个方法同时设置多个注解)
- @CacheConfig 在类级别设置一些缓存相关的共同配置(与其它缓存配合使用)
注意 :@Cacheable 默认使用标@primary 注释的CacheManage
/**
* 先查缓存,如果查不到,执行方法体并将结果写入缓存,若查到,不执行方法体,直接返回缓存结果
* @param id
*/
@Cacheable(value = "name1", key = "#id", sync = true)
public void getUser(long id){
//TODO 查找数据库
}
/**
* 更新缓存,每次都会执行方法体
* @param user
*/
@CachePut(value = "name1", key = "#user.id")
public void saveUser(User user){
//todo 保存数据库
}
/**
* 删除
* @param user
*/
@CacheEvict(value = "name1",key = "#user.id")
public void delUser(User user){
//todo 保存数据库
}
参考博客:https://www.cnblogs.com/wudiffs/p/11585757.html
(23条消息) SpringBoot 集成 Caffeine(咖啡因)最优秀的本地缓存_springboot caffeine_Listening_Wind的博客-CSDN博客https://blog.csdn.net/Listening_Wind/article/details/110085228