Caffeine缓存和@Cacheable注解
1. Caffeine的基础使⽤
1.1 简介
Caffeine是基于Java 8的⾼性能,接近最佳的缓存⼯具库。Caffeine使⽤Google Guava启发的API提供内存缓存。所以它的使⽤成本较低,跟Guava的API⼤致⼀致。
它主要有以下⼏个功能:
⾃动将条⽬⾃动加载到缓存中,可以选择同步或异步加载
基于频率和新近度超过最⼤值时基于⼤⼩的逐出
⾃上次访问或上次写⼊以来测得的基于时间的条⽬到期
发⽣第⼀个陈旧的条⽬请求时,异步刷新
键⾃动包装在弱引⽤中
值⾃动包装在弱引⽤或软引⽤中
逐出(或以其他⽅式删除)条⽬的通知
写⼊通知
缓存访问统计信息的
1.2 常见API
Cache分为LoadingCache(同步缓存),AsyncLoadingCache(异步缓存)
pom依赖
<dependency>
<groupId>com.github.benmanes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>2.8.5</version>
</dependency>
1.2.1 ⼈⼯加载策略
Cache<Object, Object> cache = wBuilder()
.expireAfterWrite(1, TimeUnit.SECONDS)
.expireAfterAccess(1, TimeUnit.SECONDS)
.maximumSize(10)//最⼤条数
.build();//定义cache
User user1=(User) (id, v-> One(id));//如果cache不存在,查询数据库
1.2.2 ⾃动加载同步
LoadingCache<String, User> userDaoCache = wBuilder().expireAfterWrite(1, TimeUnit.SECONDS)
.expireAfterAccess(1, TimeUnit.SECONDS).maximumSize(10).build(key -> One(key))
User user = ("1");
1.2.3 ⾃动加载异步
AsyncLoadingCache<String, User> asynUserDaoCache = wBuilder()
access被淘汰了吗.expireAfterWrite(1, TimeUnit.SECONDS).expireAfterAccess(1, TimeUnit.SECONDS).maximumSize(10)
.buildAsync(key -> One(key));
User user = ("1").get();
1.3. 其他API
1.3.1 统计缓存信息
Cache<Object, Object> cacheStats = wBuilder()
.expireAfterWrite(1000, TimeUnit.SECONDS)
.expireAfterAccess(1000, TimeUnit.SECONDS)
.recordStats()//记录统计信息
.weakKeys()//key弱引⽤
.weakValues()//value 弱引⽤
.maximumSize(10).build()
CacheStats stats = cacheStats.stats();//获取统计信息
1.3.2 CacheWriter
LoadingCache<String, User> cacheWriter = wBuilder().expireAfterAccess(3, TimeUnit.SECONDS)
.writer(new CacheWriter<String, User>(){
@Override
public void write(String id, User user){
System.out.println("***写⼊***"+ id);//当缓存数据时,调⽤此⽅案
}
@Override
public void delete(String id, User user, RemovalCause cause){
System.out.println("***delete***"+ id);//当⼿动删除数据时,调⽤此⽅法
}
}).build(id -> One(id));
1.3.3 RemovealListener监听(⼿动删除)
1.4. 缓存淘汰机制
常见缓存机制有:LRU(Least Recently Used)最近最少使⽤
LFU(Least Frequently Used)最不经常使⽤
1.4.1 LRU
如果⼀个数据在最近⼀段时间没有被访问到,那么认为在将来他被访问的可能性也很低,也就是说,当限定的空间已存满数据时,应当把最久没有被访问到的数据淘汰
缺点是:注重对数据的使⽤时间是不是最近,缓存数⽬超过容量,缓存数据很容易淘汰
1.4.2 LFU
如果⼀个数据在最近⼀段时间很少被访问到,那么可以认为在将来它被访问的可能性也很⼩。因此,当空间满时,最⼩频率访问的数据最先被淘汰
缺点:注重对元素的使⽤频次上是不是较⼤。
1.在短时间内如果某些元素访问频率很⾼,会导致后续很难淘汰,造成⽆效数据缓存。
2.突发流量的时候,可能由于没有及时达到⾜够的频率数据来保证⾃⼰驻留在缓存中,从⽽导致缓存的命中率下降
1.5 参数总结
maximumSize:设置缓存最⼤条⽬数,超过条⽬则触发回收
maximumWeight:设置缓存最⼤权重,设置权重是通过weigher⽅法,需要注意的是权重也是限制缓存⼤⼩的参数,并不会影响缓存淘汰策略,也不能和maxi mumSize⽅法⼀起使⽤。
weakKeys:将key设置为弱引⽤,在GC时可以直接淘汰
weakValues:将value设置为弱引⽤,在GC时可以直接淘汰
softValues:将value设置为软引⽤,在内存溢出前可以直接淘汰
expireAfterWrite:写⼊后隔段时间过期
expireAfterAccess:访问后隔断时间过期
refreshAfterWrite:写⼊后隔断时间刷新
removalListener:缓存淘汰,配置后,每个条⽬淘汰时都会调⽤该
writer:writer其实提供了两个监听,⼀个是缓存写⼊或更新是的write,⼀个是缓存淘汰时的delete,每个条⽬淘汰时都会调⽤该
2. @Cacheable注解
@Cacheable 触发缓存⼊⼝(这⾥⼀般放在创建和获取的⽅法上)
@CacheEvict 触发缓存的eviction(⽤于删除的⽅法上)
@CachePut 更新缓存且不影响⽅法执⾏(⽤于修改的⽅法上,该注解下的⽅法始终会被执⾏)
@Caching 将多个缓存组合在⼀个⽅法上(该注解可以允许⼀个⽅法同时设置多个注解)
@CacheConfig 在类级别设置⼀些缓存相关的共同配置(与其它缓存配合使⽤)
项⽬中主要使⽤的是@Cacheable注解
源码
public @interface Cacheable {
/**
* 设定要使⽤的cache的名字,必须提前定义好缓存
*/
@AliasFor("cacheNames")
String[]value()default{};
/
**
* 同value(),决定要使⽤那个/些缓存
*/
@AliasFor("value")
String[]cacheNames()default{};
/**
* 使⽤SpEL表达式来设定缓存的key,如果不设置默认⽅法上所有参数都会作为key的⼀部分
*/
String key()default"";
/**
* ⽤来⽣成key,与key()不可以共⽤
*/
String keyGenerator()default"";
/**
* 设定要使⽤的cacheManager,必须先设置好cacheManager的bean,这是使⽤该bean的名字
*/
String cacheManager()default"";
/**
* 使⽤cacheResolver来设定使⽤的缓存,⽤法同cacheManager,但是与cacheManager不可以同时使⽤    */
String cacheResolver()default"";
/**
* 使⽤SpEL表达式设定出发缓存的条件,在⽅法执⾏前⽣效
*/
String condition()default"";
/**
* 使⽤SpEL设置出发缓存的条件,这⾥是⽅法执⾏完⽣效,所以条件中可以有⽅法执⾏后的value
*/
String unless()default"";
/**
* ⽤于同步的,在缓存失效(过期不存在等各种原因)的时候,如果多个线程同时访问被标注的⽅法
* 则只允许⼀个线程通过去执⾏⽅法
*/
boolean sync()default false;
}
项⽬中的使⽤

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。