Spring对于Cache的抽象架构

Spring提供的重要缓存注解及几个重要概念:

概念/注解作用
Cache 缓存接口,定义缓存操作。实现有:RedisCache、EhCacheCache、 ConcurrentMapCache等
CacheManager 缓存管理器,管理各种缓存(Cache)组件
@Cacheable 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存
@CacheEvict 清空缓存
@CachePut 保证方法被调用,又希望结果被缓存。
@EnableCaching 开启基于注解的缓存
keyGenerator 缓存数据时key生成策略
serialize 缓存数据时value序列化策略

使用方法就是在启动类上加上@EnableCaching注解来开启缓存功能。之后就可以在方法上使用上述注解进行缓存的使用下面,我们针对几个重要注解做一下讲解。

@Cacheable

@Cacheable:将方法运行的结果进行缓存,以后再获取相同的数据时,直接从缓存中获取,不再调用方法。使用示例如下:

@Cacheable(cacheNames = {"emp"})
public Employee getEmpById(Integer id){
  Employee emp = employeeMapper.getEmpById(id);
  return emp;
}

@Cacheable注解的属性:

属性名描述
cacheNames/value 指定缓存的名字,缓存使用CacheManager管理多个缓存组件Cache,这些Cache组件就是根据这个名字进行区分的。对缓存的真正CRUD操作在Cache中定义,每个缓存组件Cache都有自己唯一的名字,通过cacheNames或者value属性指定,相当于是将缓存的键值对进行分组,缓存的名字是一个数组,也就是说可以将一个缓存键值对分到多个组里面
key 缓存数据时的key的值,默认是使用方法参数的值,可以使用SpEL表达式计算key的值
keyGenerator 缓存的生成策略,和key二选一,都是生成键的,keyGenerator可自定义
cacheManager 指定缓存管理器(如ConcurrentHashMap、Redis等)
cacheResolver 和cacheManager功能一样,和cacheManager二选一
condition 指定缓存的条件(满足什么条件时才缓存),可用SpEL表达式(如id>0,表示当入参id大于0时才缓存)
unless 否定缓存,即满足unless指定的条件时,方法的结果不进行缓存,使用unless时可以在调用的方法获取到结果之后再进行判断(如result==null,表示如果结果为null时不缓存)
sync 是否使用异步模式进行缓存

注意:

  • 既满足condition又满足unless条件的也不进行缓存

  • 使用异步模式进行缓存时(sync=true):unless条件将不被支持

可用的SpEL表达式见下表:

名字位置描述示例
methodName root object 当前被调用的方法名 #root.methodName
method root object 当前被调用的方法 #root.method.name
target root object 当前被调用的目标对象 root.target
targetClass root object 当前被调用的目标对象类 #root.targetClass
args root object 当前被调用的方法的参数列表 #root.args[0]
caches root object 当前方法调用使用的存列表 (如@Cacheable(value= {“cache1”, “cache2”})),则有两 个cache root.caches[0].name
argument name evaluation context 方法参数的名字,可以直接 #参数名,也可以使用#p0或#a0的形式,0代表参数的索引 #iban、#a0、#p0
result evaluation context 方法执行后的返回值(仅当方法 执行之后的判断有效,如"unless","cache put"的表达式,"cache evict"的表达式beforeInvocation=false) #result

@CachePut

说明:既调用方法,又更新缓存数据,一般用于更新操作,在更新缓存时一定要和想更新的缓存有相同的缓存名称和相同的key( 可类比同一张表的同一条数据)。示例如下:

@CachePut(value = "emp",key = "#employee.id")
public Employee updateEmp(Employee employee){
  employeeMapper.updateEmp(employee);
  return employee;
}

@CacheEvict

说明:缓存清除,清除缓存时要指明缓存的名字和key,相当于告诉数据库要删除哪个表中的哪条数据,key默认为参数的值。

注意allEntries属性是指是否清除指定缓存中的所有键值对,默认为false,设置为true时会清除缓存中 的所有键值对,与key属性二选一使用。beforeInvocation 指在@CacheEvict注解的方法调用之前清除指定缓存,默认为false,即在方法调用之后清除缓存。设置为true时则会在方法调用之前清除缓存( 在方法调用之前还是之后清除缓存的区别在于方法调用时是否会出现异常,若不出现异常,这两种设置没有区别,若出现异常,设置为在方法调用之后清除缓存将不起作用,因为方法调用失败了)

示例:

@CacheEvict(value = "emp",key = "#id",beforeInvocation = true)
public void delEmp(Integer id){
  employeeMapper.deleteEmpById(id);
}

@CacheConfig

作用:标注在类上,抽取缓存相关注解的公共配置,可抽取的公共配置有缓存名字、主键生成器等(如注解中的属性所示):

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CacheConfig {
String[] cacheNames() default {};
String keyGenerator() default "";
String cacheManager() default "";
String cacheResolver() default "";
}

示例:通过@CacheConfig的cacheNames 属性指定缓存的名字之后,该类中的其他缓存注解就不必再写value或者cacheName了,会使用该名字作为value或cacheName的值,当然也遵循就近原则:

@Service
@CacheConfig(cacheNames = "emp")
public class EmployeeService {

  @Autowired
  EmployeeMapper employeeMapper;

  @Cacheable
  public Employee getEmpById(Integer id) {
      Employee emp = employeeMapper.getEmpById(id);
      return emp;
  }

  @CachePut(key = "#employee.id")
  public Employee updateEmp(Employee employee) {
      employeeMapper.updateEmp(employee);
      return employee;
  }

  @CacheEvict(key = "#id", beforeInvocation = true)
  public void delEmp(Integer id) {
      employeeMapper.deleteEmpById(id);
  }
}
 

posted on 2023-07-01 00:07  中二的火系魔法师  阅读(22)  评论(0编辑  收藏  举报

导航