Spring Cache是什么?
Spring Cache 是一个非常优秀的缓存组件。自Spring 3.1起,提供了类似于@Transactional注解事务的注解Cache支持,且提供了Cache抽象,方便切换各种底层Cache(如:redis)
Spring Cache的好处
1,提供基本的Cache抽象,方便切换各种底层Cache;
2,通过注解Cache可以实现类似于事务一样,缓存逻辑透明的应用到我们的业务代码上,且只需要更少的代码就可以完成;
3,提供事务回滚时也自动回滚缓存;
4,支持比较复杂的缓存逻辑;
Spring Cache支持的缓存类型
@Bean
public EhCacheCacheManager cacheManager(CacheManager ehCacheCacheManager) {
return new EhCacheCacheManager(ehCacheCacheManager);
}
Spring Cache常用的缓存注释
@EnableCaching:
标记注解 @EnableCaching,开启缓存,并配置Redis缓存管理器。@EnableCaching 注释触发后置处理器,检查每一个Spring bean 的 public 方法是否存在缓存注解。如果找到这样的一个注释,
自动创建一个代理拦截方法调用和处理相应的缓存行为。
缓存@Cacheable
根据方法对其返回结果进行缓存,下次请求时,如果缓存存在,则直接读取缓存数据返回;如果缓存不存在,则执行方法,并把返回的结果存入缓存中。一般用在查询方法上。
属性值如下:
缓存@CachePut
使用该注解标志的方法,每次都会执行,并将结果存入指定的缓存中。其他方法可以直接从响应的缓存中读取缓存数据,而不需要再去查询数据库。一般用在新增方法上。
缓存@CacheEvict
缓存应用流程
- 通过缓存提供者CachingProvider得到缓存管理器CacheManager;
- 缓存提供者可以管理多个缓存管理器;
- 每个缓存管理器管理特定类型的缓存;比如:CacheManager1管理redis缓存、CacheManager2管理memcache缓存;
- 缓存管理器用来管理缓存Cache;
- 一个缓存管理器管理多个缓存;比如:Cache1用来保存员工数据、Cache2用来缓存部门数据;
- 缓存中保存多条数据,每一条数据是一个键值对;
- Cache接口中提供了一些api,用来对数据进行增删改查操作;
什么样的数据适合放入缓存
什么样的数据需要放进缓存呢?把数据放入缓存,有三个标准:
- 数据量不大
- 访问频率高
- 数据更改频率低
常用的本地缓存
本地缓存 | 介绍 |
Caffeine | 是使用 对 缓存的重写版本,在 中将取代 ,基于 算法实现,支持多种缓存过期策略。 |
ehcache | 是一个纯 的进程内缓存框架,具有快速、精干等特点,是 中默认的 。 |
GuavaCache | 工具包中的一个非常方便易用的本地化缓存实现,基于 算法实现,支持多种缓存过期策略。 |
常用的本地缓存测试比较
测试逻辑:
- 构建Cache,load方法为简单的字符串拼接
- 将250000个字符串加载到cache后,启动任务线程,预热10s后,开始计时,统计每10秒的count,共6轮,最后统计每轮中的每秒平均值
测试结果:
(1) 6个线程纯读:
(2) 4个线程读+2个线程写:
压测对比
运行环境:MacBook
Pro i7-4870HQ CPU @ 2.50GHz (4 core) 16 GB
读操作
在这个基准测试中,8个线程同时从配置了最大大小的缓存中读取。
写操作
在这个基准测试中,8个线程同时写入一个配置了最大大小的缓存。
读
Unbounded | ops/s (8 threads) | ops/s (16 threads) |
ConcurrentHashMap (v8) | 560,367,163 | 1,171,389,095 |
ConcurrentHashMap (v7) | 301,331,240 | 542,304,172 |
Bounded | ||
Caffeine | 181,703,298 | 382,355,194 |
ConcurrentLinkedHashMap | 154,771,582 | 313,892,223 |
LinkedHashMap_Lru | 9,209,065 | 13,598,576 |
Guava (default) | 12,434,655 | 10,647,238 |
Guava (64) | 24,533,922 | 43,101,468 |
Ehcache2_Lru | 11,252,172 | 20,750,543 |
Ehcache3_Lru | 11,415,248 | 17,611,169 |
Infinispan_Old_Lru | 29,073,439 | 49,719,833 |
Infinispan_New_Lru | 4,888,027 | 4,749,506 |
写
Unbounded | ops/s (8 threads) | ops/s (16 threads) |
ConcurrentHashMap (v8) | 60,477,550 | 50,591,346 |
ConcurrentHashMap (v7) | 46,204,091 | 36,659,485 |
Bounded | ||
Caffeine | 55,281,751 | 48,295,360 |
ConcurrentLinkedHashMap | 23,819,597 | 39,797,969 |
LinkedHashMap_Lru | 10,179,891 | 10,859,549 |
Guava (default) | 4,764,056 | 5,446,282 |
Guava (64) | 8,128,024 | 7,483,986 |
Ehcache2_Lru | 4,205,936 | 4,697,745 |
Ehcache3_Lru | 10,051,020 | 13,939,317 |
Infinispan_Old_Lru | 7,538,859 | 7,332,973 |
Infinispan_New_Lru | 4,797,502 | 5,086,305 |
本地缓存推荐
Caffeine是在guava基础上进行优化的产物,也是带着替代guava的目的而来的,因而在使用上差别不大,但是通过测试可以明显看到Caffeine在性能上的优势。
Caffeine是Spring 5默认支持的Cache,可见Spring对它的看重。
Caffine是什么?
Caffeine是⼀个基于Java
8的⾼性能,接近最佳的缓存库。
Caffine有什么特⾊?
- ⾃动将条⽬加载到缓存中,可选择异步加载
- 基于频率和新近度超过最⼤值时的基于⼤⼩的驱逐
- ⾃上次访问或上次写⼊以来测量的条⽬的基于时间的到期
- 当第⼀个条⽬的陈旧请求发⽣时,异步刷新
- 密钥⾃动包含在弱引⽤中
- 值⾃动包含在弱引⽤或软引⽤中
- 被驱逐(或以其他⽅式删除)条⽬的通知
- 写⼊传播到外部资源
- 累积缓存访问统计信息