Spring Boot与缓存
JSR107
Spring缓存抽象
Spring简化了JSR107的操作,让我们可以更加轻松的开发
引入依赖:
1 | <dependency> |
使用注释@EnableCaching
开启缓存
cacheManager
默认使用的是ConcurrentMapCacheManager==ConcurrentMapCache
,将数据保存在ConcurrentMap<Object, Object>
中
配置:
- 自动配置类;CacheAutoConfiguration
- 缓存的配置类
- org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration
- org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration
- org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration
- org.springframework.boot.autoconfigure.cache.HazelcastCacheConfiguration
- org.springframework.boot.autoconfigure.cache.InfinispanCacheConfiguration
- org.springframework.boot.autoconfigure.cache.CouchbaseCacheConfiguration
- org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration
- org.springframework.boot.autoconfigure.cache.CaffeineCacheConfiguration
- org.springframework.boot.autoconfigure.cache.GuavaCacheConfiguration
- org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration[默认]
- org.springframework.boot.autoconfigure.cache.NoOpCacheConfiguration
@Cacheable
然后在需要缓存的方法上@Cacheable
来进行缓存
1 | "employee", condition = "#id>0", unless = "#result == null") (cacheNames = |
注意一定要有cacheNames来指定使用至少一个cache,如果cacheManager中没有这个cache,就会自动创建,默认的key是方法参数的值,value是方法的返回值,到第二次通过相同的参数使用这个方法时,就会在cache中抽取而不调用方法。
可以指定key或keyGenerator来自定义自己的key名,key名支持SpEL,例如要是使用上面的id的值,可以
#id
来指定参数名为id的参数,也可以#a0
,#p0
,#root.args[0]
来指定第一个参数也可以使用condition或unless来判断,只有满足情况才缓存,如上所示
使用sync来指定是否使用异步模式,异步模式下不能使用unless
@Cacheable主要的参数
名称 | 解释 |
---|---|
value/cacheNames | 缓存的名称,在 spring 配置文件中定义,必须指定至少一个。@Cacheable(value=”mycache”) 或者 @Cacheable(value={”cache1”,”cache2”} |
key | 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写, 如果不指定,则按照方法的所有参数进行组合。 @Cacheable(value=”testcache”,key=”#id”) |
condition | 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false, 只有为 true 才进行缓存@Cacheable(value=”testcache”,condition=”#userName.length()>2”) |
unless | 否定缓存。当条件结果为TRUE时,就不会缓存。 @Cacheable(value=”testcache”,unless=”#userName.length()>2”) |
cacheManager/cacheResolver | 指定使用哪一个cacheManager(一般是自定义的) |
SpEL上下文数据
名称 | 位置 | 描述 | 示例 |
---|---|---|---|
methodName | root对象 | 当前被调用的方法名 | #root.methodname 、#root.method.name |
method | root对象 | 当前被调用的方法 | #root.method |
target | root对象 | 当前被调用的目标对象实例 | #root.target |
targetClass | root对象 | 当前被调用的目标对象的类 | #root.targetClass |
args | root对象 | 当前被调用的方法的参数列表 | #root.args[0] 、#a0 、#p0 |
caches | root对象 | 当前方法调用使用的缓存列表 | #root.caches[0].name |
Argument Name | 执行上下文 | 当前被调用的方法的参数,如findArtisan(Artisan artisan) ,可以通过#artsian.id 获得参数 |
#artsian.id |
result | 执行上下文 | 方法执行后的返回值(仅当方法执行后的判断有效,如 unless cacheEvict的beforeInvocation=false) | #result |
- 方法运行之前,先去查询Cache(缓存组件),按照cacheNames指定的名字获取;
- (CacheManager先获取相应的缓存),第一次获取缓存如果没有Cache组件会自动创建。
- 去Cache中查找缓存的内容,使用一个key,默认就是方法的参数;
- key是按照某种策略生成的,默认是使用keyGenerator生成的
- 默认的keyGenerator是SimpleKeyGenerator
- SimpleKeyGenerator生成key的默认策略:
- 如果没有参数:key=SimpleKey.Empty,即key=new SimpleKey(),一个空的SimplyKey对象
- 如果只有一个参数:key=param,这个参数值
- 如果有多个参数:key=new SimpleKey(params),创建一个SimplyKey对象存所有的参数
- 没有查到缓存就调用目标方法
- 将目标方法返回的结果,放进缓存中
@Cacheable
标注的方法执行之前先来检查缓存中有没有这个数据,默认按照参数的值作为key去查询缓存,如果没有就运行方法并将结果放入缓存,以后再来调用就可以直接使用缓存中的数据。因此@Cacheable
的key
属性不能使用#result
,因为在方法调用前就要确定key的值。
@CachePut
既调用方法,又更新缓存。与Cacheable不同的是,它会先调用方法,然后把方法的返回值放进缓存中,参数与@Cacheable类似,不同的是key的值可以使用#result
1 | "emp",key = "#result.id") (value = |
@CacheEvict
用于删除缓存,相比@Cacheable
而言多了下面2个属性
名称 | 解释 |
---|---|
allEntries | 是否清空所有缓存内容,缺省为 false,如果指定为 true, 则方法调用后将立即清空所有缓存@CachEvict(value=”testcache”,allEntries=true) |
beforeInvocation | 是否在方法执行前就清空,缺省为 false,如果指定为 true, 则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法 执行抛出异常,则不会清空缓存@CachEvict(value=”testcache”,beforeInvocation=true) |
@Caching
@Caching
用于定义复杂的缓存规则,例如要同时使用多个注释组合时可以:
1 | ( |
表示以lastName为key放入缓存的同时分别把以id和email为key的缓存也放入缓存。但是因为这里使用了@CachePut
,所以无论缓存中有没有以lastName为key的记录都会调用方法。
@CacheConfig
用于配置当前类下的所有Cache注释的公共属性
1 | "emp",cacheManager = "employeeCacheManager") (cacheNames= |
然后在类里的Cache注释,就可以省略公共属性
整合Redis
一如既往:
1 | <dependency> |
然后设置Redis的位置(这里我是在阿里云服务器上使用docker建了一个redis映射到6380端口)
1 | spring: |
注意redis的key和value都需要序列化,要给bean实现一个Serializable
接口,否则会弹出无法序列化的错误。若要直接操作redis,可以让Spring自动注入一个redisTemplate
来进行操作
1 |
|
如果要自定义redis配置(例如定义序列化和反序列化格式),可以给容器中添加一个RedisTemplate
和RedisCacheManager
的bean。如下所示
1 |
|
1 |
|
如果要使用这个cacheManager,可以在使用缓存的类中用cacheManager
属性指定。