SpringIT必备技能

SpringBoot缓存注解@Cacheable、@CacheE

2020-06-25  本文已影响0人  Djbfifjd

一、简述

从3.1开始,Spring引入了对Cache的支持。其使用方法和原理都类似于Spring对事务管理的支持。Spring Cache是作用在方法上的,其核心思想是这样的:当调用一个缓存方法时,会把该方法参数和返回结果作为一个键值对存放在缓存中,等到下次利用同样的参数来调用该方法时将不再执行该方法,而是直接从缓存中获取结果进行返回。所以在使用Spring Cache的时候,要保证缓存的方法对于相同的方法参数要有相同的返回结果。使用Spring Cache需要做到两点:

1️⃣在Springboot的启动类上使用@EnableCaching//开启缓存
2️⃣声明某些方法使用缓存

和Spring对事务管理的支持一样,Spring对Cache的支持也有基于注解和基于XML配置两种方式。

二、基于注解的支持

Spring提供了几个注解来支持Spring Cache。其核心主要是@Cacheable和@CacheEvict。使用@Cacheable标记的方法在执行后,Spring Cache将缓存其返回结果,而使用@CacheEvict标记的方法会在方法执行前或者执行后移除Spring Cache中的某些元素。

1️⃣@Cacheable
@Cacheable可以标记在类上或者方法上。当标记在方法上时表示该方法是支持缓存的,当标记在类上时则表示该类所有的方法都是支持缓存的。对于一个支持缓存的方法,Spring会在其被调用后将其返回值缓存起来,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果,而不需要再次执行该方法。Spring在缓存方法的返回值时是以键值对进行缓存的,值就是方法的返回结果,至于键的话,Spring又支持两种策略,默认策略和自定义策略。需要注意的是当一个支持缓存的方法在对象内部被调用时是不会触发缓存功能的。@Cacheable可以指定三个属性,value、key和condition。

【value属性指定Cache名称】
value是必须指定的,其表示当前方法的返回值被缓存在哪个Cache上,对应Cache的名称。其可以是一个Cache也可以是多个Cache,当需要指定多个Cache时其是一个数组。

@Cacheable("cache1")//Cache是发生在cache1上的
public User find(Integer id) {
    return null;
}
@Cacheable({"cache1", "cache2"})//Cache是发生在cache1和cache2上的
public User find(Integer id) {
    return null;
}

【使用key属性自定义key】
key属性是用来指定Spring缓存方法的返回结果时对应的key的。该属性支持SpringEL表达式。当没有指定该属性时,Spring将使用默认策略生成key。
自定义策略是指可以通过Spring的EL表达式来指定key。这里的EL表达式可以使用方法参数及它们对应的属性。使用方法参数时可以直接使用#参数名或者#p参数index。如下示例:

//key是指传入时的参数
@Cacheable(value="users", key="#id")
public User find(Integer id) {
    return null;
}
// 表示第一个参数
@Cacheable(value="users", key="#p0")
public User find(Integer id) {
    return null;
}
// 表示User中的id值
@Cacheable(value="users", key="#user.id")
public User find(User user) {
    return null;
}
// 表示第一个参数里的id属性值
@Cacheable(value="users", key="#p0.id")
public User find(User user) {
   return null;
}

除了上述使用方法参数作为key之外,Spring还提供了一个root对象可以用来生成key。通过该root对象可以获取到以下信息。

当要使用root对象的属性作为key时,也可以将“#root”省略,因为Spring默认使用的就是root对象的属性。如:

// key值为:user中的name属性的值
@Cacheable(value={"users", "xxx"}, key="caches[1].name")
public User find(User user) {
    return null;
}

【condition属性指定发生的条件】
有时候可能并不希望缓存一个方法的所有返回结果。condition属性默认为空,表示将缓存所有的调用情形。其值是通过SpringEL表达式来指定的,当为true时表示进行缓存处理;当为false时表示不进行缓存处理,即每次调用该方法时该方法都会执行一次。如下表示只有当user的id为偶数时才会缓存:

// 根据条件判断是否缓存
@Cacheable(value={"users"}, key="#user.id", condition="#user.id%2==0")
public User find(User user) {
   System.out.println("find user by user " + user);
   return user;
}

2️⃣@CachePut
在支持Spring Cache的环境下,对于使用@Cacheable标注的方法,Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素,如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,否则才会执行并将返回结果存入指定的缓存中。@CachePut也可以声明一个方法支持缓存功能。与@Cacheable不同的是使用@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。

//@CachePut也可以标注在类或方法上。可以指定的属性跟@Cacheable是一样的
@CachePut("users")//每次都会执行方法,并将结果存入指定的缓存中
public User find(Integer id) {
   return null;
}

3️⃣@CacheEvict
@CacheEvict是用来标注在需要清除缓存元素的方法或类上的。当标记在一个类上时表示其中所有的方法的执行都会触发缓存的清除操作。@CacheEvict可以指定的属性有value、key、condition、allEntries和beforeInvocation。其中value、key和condition的语义与@Cacheable对应的属性类似。即value表示清除操作是发生在哪些Cache上的(对应Cache的名称);key表示需要清除的是哪个key,如未指定则会使用默认策略生成的key;condition表示清除操作发生的条件。
【allEntries属性】
allEntries是boolean类型,表示是否需要清除缓存中的所有元素。默认为false,表示不需要。当指定了allEntries为true时,Spring Cache将忽略指定的key。有的时候需要Cache一下清除所有的元素,这比一个一个清除元素更有效率。

@CacheEvict(value="users", allEntries=true)
public void delete(Integer id) {
   System.out.println("delete user by id: " + id);
}

【beforeInvocation属性】
清除操作默认是在对应方法成功执行之后触发的,如果方法抛出异常而未能成功返回时不会触发清除操作。使用beforeInvocation可以改变触发清除操作的时间,当指定该属性值为true时,Spring会在调用该方法之前清除缓存中的指定元素。

@CacheEvict(value="users", beforeInvocation=true)
public void delete(Integer id) {
   System.out.println("delete user by id: " + id);
}

其实除了使用@CacheEvict清除缓存元素外,当使用Ehcache作为实现时,也可以配置Ehcache自身的清除策略,其是通过Ehcache的配置文件来指定的。

4️⃣@Caching
@Caching注解可以在一个方法或者类上同时指定多个Spring Cache相关的注解。其拥有三个属性:cacheable、put和evict,分别用于指定@Cacheable、@CachePut和@CacheEvict。

@Caching(cacheable = @Cacheable("users"), evict = { @CacheEvict("cache2"),
@CacheEvict(value = "cache3", allEntries = true) })
public User find(Integer id) {
   return null;
}

5️⃣使用自定义注解
Spring允许在配置可缓存的方法时使用自定义的注解,前提是自定义的注解上必须使用对应的注解进行标注。如有如下这么一个使用@Cacheable进行标注的自定义注解:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Cacheable(value="users")
public @interface MyCacheable {
}

那么在需要缓存的方法上使用@MyCacheable进行标注也可以达到同样的效果。

@MyCacheable
public User findById(Integer id) {
    System.out.println("find user by id: " + id);
    User user = new User();
    user.setId(id);
    user.setName("Name" + id);
    return user;
}

三、应用场景

1️⃣@CachePut:更新数据库的数据并更新缓存

  1. 先调用更新数据库方法
  2. 再将更新的数据写入名为(users)缓存中
@PostMapping(value = "/updateUserInfo")
@CachePut(value = "users", key = "#user.userId")
public void updateUserInfo(User user) {
   userService.updateUserInfo(user);
}

2️⃣@Cahceable:查询出的数据是最新的而不是之前缓存中的

  1. 这里value属性的值同@CachePut时的value值一样,确保查询与更新都是同一块缓存。
  2. 此时查询的key要和更新的key保持一致,确保拿到的是更新后的数据。
@GetMapping(value = "/queryUserInfo/{userId}")
@Cacheable(value = "users", key = "#userId")
public User queryUserInfo(@PathVariable("userId")Integer userId) {
   userService.queryUserInfo(userId);
}
上一篇下一篇

猜你喜欢

热点阅读