前置知识:
- 在Spring Cache缓存中有两大组件CacheManager和Cache.在整个缓存中可以有多个CacheManager,他们负责管理他们里边的Cache。一个CacheManager中可以创建多个Cache,每个Cache负责存储一个种类数据,例如Salary Cache负责存储Salary相关的数据。
步骤:
一、开启基于注解的缓存功能
在启动类或者其他配置类中加入@EnabeleCaching注解
@SpringBootApplication @MapperScan("com.xj.springboot.mapper") @EnableCaching public class SpringbootCacheApplication { public static void main(String[] args) { SpringApplication.run(SpringbootCacheApplication.class, args); } }
二、在方法上标注缓存注解
1.@Cacheable
此注解可以标注在方法上,当第一次调用被@Cacheable注解标注的方法时,该注解会将方法的返回值作为value存入缓存中,如果没有指定key,则key默认值为方法的实参(注意不是形参)。然后再次调用此方法,传入的参数和上一次一样,则不会再执行方法体中的代码,而是直接从缓存中取出数据,然后返回。
cacheable注解中有9个属性:value、cacheNames、key、keyGenerator、cacheManager、cacheResolver、condition、unless、sync。其中value和cacheNames互为别名,所以可以说只有8个属性。
- value / cacheNames:用于指定Cache的名字,此属性是数组类型,可以指定多个缓存的名字。此属性必须指定,不设置会报错。
- key:用于指定存放进缓存的数据的key(因为要将当前方法的返回值以key-value的形式存储在缓存中),不设置的话默认就是传入方法的实参的值(注意不是形参),如果要设置通常会使用spEL表达式(spEL可参考下图)。
注意:@Cacheable注解的key属性中不能使用#result取出方法执行后的返回值,因为@Cacheable注解是先到缓存中查找,在执行方法的,在没执行方法前,#result是取不到值的。
- keyGenerator:用于指定key的生成器。注意,keyGenerator和key只能同时存在一个,如果设置了key,则不能再设置keyGenerator。
- cacheManager:指定使用哪个CacheManager(缓存管理器)。springboot的自动配置在容器中添加了一个ConcurrentMapCacheManager类型的cacheManager,如果我们没有指定cacheManager,则默认使用springboot提供的,即ConcurrentMapCacheManager。
- cacheResolver:作用同cacheManager。
- condition:用于指定一个表达式,当表达式成立时,才将方法的返回值放入缓存中。表达式通常同spEL表达式来编写。
- unless:作用与condition属性相反。指定一个表达式,当表达式成立时,方法的返回值将不被放入缓存中。有一点和condition不同,就是unless的表达式中,可以获取到方法的返回值进行判断。
- sync:是否使用异步模式。如果设置此注解为true(即开启异步模式)unless属性就不能使用了。多线程并发时可启用此属性。
执行流程总结:
调用方法前,会先拿注解中cacheNames属性指定的名字到缓存中查找有没有该名字的cache,如果有,则直接返回key为方法实参的数据。如果没有,那么就创建名字为cacheNames属性指定的名字的cache,然后执行方法体,将方法的返回结果作为value放到缓存中。
2.@CachePut
此注解可以标注在方法上,当每次调用被@Cacheput注解标注的方法时,该注解会都会将方法的返回值作为value存入缓存中。一般标注在执行数据库更新操作的方法上。
CachePut与Cacheable注解的区别:Cacheable只有在第一次调用方法时才会将方法返回值放到缓存中,再次调用时缓存中有就不会再执行方法体了。而CachePut每次调用方法,都会将方法返回值放入缓存中。
cachePut注解中有9个属性,这9个属性同Cacheable注解的属性使用相同。
3.CacheEvict
cacheevict中evict是驱逐,逐出的意思。所以此注解是用于删除缓存中指定key的数据的。此注解可以标注在方法上,当调用被@CacheEvict注解标注的方法时,该注解会根据 Cacheevict注解中key属性所指定的key去缓存中找到这个key对应的value,然后将它删掉。
Cacheevict注解有9个属性:value、cacheNames、key、keyGenerator、cacheManager、cacheResolver、condition、allEntries、beforeInvocation。其中,前7个属性和@Cacheable中的属性作用是一样的,下边就不再赘述了,只介绍allEntries和beforeInvocation
- allEntries:当allEntries设置为true时,表示调用当前注解标注的方法会将cacheNames指定的cache中所有的缓存数据全部清除。默认为false
- beforeInvocation:当beforeInvocation设置为true时,清除缓存数据这个动作会在方法被调用之前执行。默认值为false,即先调用方法,执行方法中的内容,最后执行清除缓存数据的动作。也许你还是疑惑beforeInvocation到底有什么用,清除缓存数据的动作在方法调用之前执行和在方法调用之后执行有什么区别。答案是肯定有区别的,区别就是清除缓存数据的动作在方法调用之后的话,会先执行方法,此时如果方法出现异常,就不会再执行清除缓存数据的动作。而清除缓存数据的动作在方法调用之前,那么不管方法会不会出现异常,清除缓存数据的动作都会执行。
4.@Caching
此注解起始就是Cacheable、CachePut、CacheEvict这三个注解的组合体。此注解适用于缓存复杂的方法上。下边是Caching注解的源码。
@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface Caching { Cacheable[] cacheable() default {}; CachePut[] put() default {}; CacheEvict[] evict() default {}; }
5.@CacheConfig
此注解可以标注在类上,用于抽取缓存的公共配置。
如果一个类中的所有方法上的Cacheable、CachePut、CacheEvict这三个注解,他们的都是cacheNames都是指向同一个或者同一批cache的,那么就可以用把@CacheConfig注解这些cacheNames都抽取出来,然后将此注解标注在类上。那么,这个类下边的方法上的缓存相关就都不用再指定cacheNames属性了,都会使用CacheConfig上指定的cacheNames。