文章目录
前言
Spring从3.1开始定义了org.springframework.cache.Cache和org.springframework.cache.CacheManager接口来统一不同的缓存技术,并支持使用JCache(JSR-107)注解简化我们开发。
一、两个核心接口
CacheManager:
定义了创建、配置、获取、管理和控制多个唯一命名的Cache,这些Cache存在于CacheManager的上下文中。一个CacheManager仅被一个CachingProvider所拥有。
Cache:
是一个类似Map的数据结构并临时存储以Key为索引的值。一个Cache仅被一个CacheManager所拥有。此外Cache接口下Spring还提供了各种xxxCache的实现;如RedisCache,EhCacheCache , ConcurrentMapCache等。
二、快速体验缓存步骤
1、添加依赖文件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
2、开启基于注解的缓存
@EnableCaching
public class SpringbootApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootApplication.class, args);
}
}
3、标注缓存注解即可
package com.test.cache.service;
import com.test.cache.bean.Employee;
import org.springframework.cache.annotation.*;
import org.springframework.stereotype.Service;
@CacheConfig(cacheNames = "emp")
@Service
public class EmployeeService {
@Cacheable(value = {"emp"},key = "#id")
public Employee getEmployee(String id) {
System.out.println("getEmployee:" + id);
return null;
}
@CachePut(key = "#result.id")
public Employee updateEmployee(Employee employee) {
System.out.println("updateEmployee:" + employee);
return null;
}
@CacheEvict(value = "emp", beforeInvocation = true)
public void deleteEmployee(String id) {
System.out.println("deleteEmployee:" + id);
}
@Caching(cacheable = {@Cacheable(key = "#lastName")}, put = {@CachePut(key = "#result.id"), @CachePut(key = "#result.email")})
public Employee getEmpByLastName(String lastName) {
System.out.println("getEmpByLastName:" + lastName);
return null;
}
}
提示:每次调用需要缓存功能的方法时,Spring会检查指定参数的指定的目标方法是否已经被调用过;如果有就直接从缓存中获取方法调用后的结果,如果没有就调用方法并缓存结果后返回给用户。下次调用直接从缓存中获取。
上述代码中@Cacheable、@CachePut、@CacheEvict、@Caching、@CacheConfig注解都有什么作用以及每个注解的属性都代表什么意思该如何使用呢?别急,我们下面开始进行缓存相关注解的详细解释……
三、缓存相关注解详解
1、@Cacheable
㈠、作用
方法执行之前先来检查缓存中有没有这个数据,默认按照参数的值作为key去查询缓存,如果没有就运行方法并将结果放入缓存;以后再来调用就可以直接使用缓存中的数据;
㈡、属性
①.cacheNames/value:指定缓存组件的名字,将方法的返回结果放在哪个缓存中,是数组的方式,可以指定多个缓存。
②.key:缓存数据使用的key可以用它来指定,默认是使用方法参数的值。可以使用SpEL表达式:
如 key = “#id” 等同于 key = “#a0” 或 key = “#p0” 或 key = "#root.args[0]"表示取出参数id的值,详细可以有哪些写法呢?如下图:
提示:@Cacheable的key是不能用#result,因为@Cacheable会先根据key去缓存中查询,如果没有就创建缓存。如果使用#result则表示结果值还没有就拿结果值做缓存很明显不合理
③.keyGenerator:key的生成器,可以自己指定key的生成器的组件id。key/keyGenerator:二选一使用;
如果想自定义key的生成策略该怎么做呢?比如让key的生成方式如:getEmployee[x]
@Configuration
public class MyCacheConfig {
@Bean("myKeyGenerator")
public KeyGenerator keyGenerator(){
return new KeyGenerator(){
@Override
public Object generate(Object target, Method method, Object... params) {
return method.getName()+"["+ Arrays.asList(params).toString()+"]";
}
};
}
/**
* 注意此方法应该放在service中喔,只是我偷懒所以放在了这里,
* 注意看keyGenerator属性是Bean的名称
*/
@Cacheable(value = {"emp"},keyGenerator = "myKeyGenerator")
public Employee getEmployee(String id) {
System.out.println("getEmployee:" + id);
return null;
}
}
④.cacheManager:指定缓存管理器,或者cacheResolver指定获取解析器
⑤.condition:指定符合条件的情况下才缓存;
如:condition = “#id>0”:第一个参数的值大于0的时候才进行缓存;condition = “#a0>1”:第一个参数的值大于1的时候才进行缓存
⑥.unless:否定缓存;当unless指定的条件为true,方法的返回值就不会被缓存;unless也可以获取到结果进行判断。
如:unless = “#result == null”:如果方法返回结果值是null,结果不缓存;unless = “#a0==2”:如果第一个参数的值是2,结果不缓存;
⑦.sync:是否使用异步模式
提示:sync异步模式下不支持unless 属性,sync与unless两者用其一
㈢、运行流程
①.方法运行之前,先去查询Cache(缓存组件),按照cacheNames指定的名字获取;(CacheManager先获取相应的缓存),第一次获取缓存如果没有Cache组件会自动创建。
②.去Cache中查找缓存的内容,使用一个key,默认就是方法的参数;key是按照某种策略生成的;默认是使用keyGenerator生成的,默认使用SimpleKeyGenerator生成key;
SimpleKeyGenerator生成key的默认策略;
如果没有参数:key=new SimpleKey()
如果有一个参数:key=参数的值
如果有多个参数:key=new SimpleKey(params)
③.没有查到缓存就调用目标方法;
④.将目标方法返回的结果,放进缓存中;
2、@CachePut
㈠、作用
先调用方法,修改了数据库的数据后,同时更新缓存;
㈡、属性
参考本章@Cacheable属性
提示:使用@CachePut(value = "emp",key = "#result.id")注解更新数据时,记得value一定要与@Cacheable的缓存名称和key值一致,不然获取值时不是更新后的值
3、@CacheEvict
㈠、作用
缓存清除
㈡、属性
①.key:指定要清除的数据。
②.allEntries:默认为false,为true时清除这个缓存中所有的数据。
③.beforeInvocation:默认为false,为false时代表缓存清除操作是在方法执行之后执行,如果出现异常缓存就不会清除。为true时代表清除缓存操作是在方法运行之前执行,无论方法是否出现异常,缓存都清除。
4、@Caching
㈠、作用
定义复杂的缓存规则,就是@Cacheable、@CachePut、@CacheEvict的组合注解,其中三个属性都是数组形式。
㈡、属性
①.@Cacheable:参考本章@Cacheable解释
②.@CachePut:参考本章@CachePut解释
③.@CacheEvict:参考本章@CacheEvict解释
5、@CacheConfig
㈠、作用
抽取缓存的公共配置,标记类时此类所有带有缓存注解的方法都无需再配置属性。
㈡、属性
①.cacheNames:指定缓存组件的名字,将方法的返回结果放在哪个缓存中,是数组的方式,可以指定多个缓存。
②.keyGenerator:key的生成器,可以自己指定key的生成器的组件id。
③.cacheManager:指定缓存管理器,或者cacheResolver指定获取解析器。
总结
@Cacheable核心
1)、springboot缓存默认使用CacheManager【ConcurrentMapCacheManager】按照名字得到Cache【ConcurrentMapCache】组件将数据保存在 ConcurrentMap<Object, Object>中
2)、key使用keyGenerator生成的,默认是SimpleKeyGenerator