原创

Spring Boot 2.缓存框架(二):Cache注解详解

前文

从Spring 3 + 开始,Spring引入了对Cache的支持。其使用方法和原理都类似于Spring对事务管理的支持。

Spring Cache是作用在方法上的,其核心思想是这样的:当我们在调用一个缓存方法时会把该方法参数和返回结果作为一个键值对存放在缓存中,等到下次利用同样的参数来调用该方法时将不再执行该方法,而是直接从缓存中获取结果进行返回。

所以在使用Spring Cache的时候我们要保证我们缓存的方法对于相同的方法参数要有相同的返回结果。

Cache配置注解详解

Spring为我们提供了几个注解来支持Spring Cache。

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

@CacheConfig

@CacheConfig:主要用于配置该类中会用到的一些共用的缓存配置。
例如:@CacheConfig(cacheNames = "users"):配置了该数据访问对象中返回的内容将存储于名为 users 的缓存对象中,我们也可以不使用该注解,直接通过@Cacheable自己配置缓存集的名字来定义。

@Cacheable

@Cacheable:@Cacheable可以标记在一个方法上,也可以标记在一个类上。当标记在一个方法上时表示该方法是支持缓存的,当标记在一个类上时则表示该类所有的方法都是支持缓存的。

对于一个支持缓存的方法,Spring会在其被调用后将其返回值缓存起来,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果,而不需要再次执行该方法。

Spring在缓存方法的返回值时是以键值对进行缓存的,值就是方法的返回结果。

键,Spring又支持两种策略,默认策略和自定义策略。

需要注意的是当一个支持缓存的方法在对象内部被调用时是不会触发缓存功能的。

@Cacheable 常用的三个属性:value、key和condition。

参数 描述 示例
value、cacheNames 缓存的名称,value、cacheNames 两个等同的参数(cacheNames为Spring 4新增,作为value的别名),用于指定缓存存储的集合名。由于Spring 4中新增了@CacheConfig,因此在Spring 3中原本必须有的value属性,也成为非必需项了 例如:
@Cacheable(value=”mycache”)
@Cacheable(value={”cache1”,”cache2”}
key 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 @Cacheable(value=”testcache”,key=”#userName”)
condition 缓存对象的条件,非必需,也需使用SpEL表达式,只有满足表达式条件的内容才会被缓存. 返回 true 或者 false,只有为 true 才进行缓存 @Cacheable(value=”testcache”,
condition=”#userName.length()>2”)
unless 另外一个缓存条件参数,非必需,需使用SpEL表达式。它不同于condition参数的地方在于它的判断时机,该条件是在函数被调用之后才做判断的,所以它可以通过对result进行判断。
keyGenerator 用于指定key生成器,非必需。若需要指定一个自定义的key生成器,我们需要去实现org.springframework.cache.interceptor.KeyGenerator接口,并使用该参数来指定。需要注意的是:该参数与key是互斥的
cacheManager 用于指定使用哪个缓存管理器,非必需。只有当有多个时才需要使用
cacheResolver 用于指定使用那个缓存解析器,非必需。需通过org.springframework.cache.interceptor.CacheResolver接口来实现自己的缓存解析器,并用该参数指定。

@Cacheable 中 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对象我们可以获取到以下信息。

属性 描述 示例
methodName 当前方法名 #root.methodName
method 当前方法 #root.method.name
target 当前被调用的对象 #root.target
targetClass 当前被调用的对象的class #root.targetClass
args 当前方法参数组成的数组 #root.args[0]
caches 当前被调用的方法使用的Cache #root.caches[0].name

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

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

更多关于SpEL表达式的详细内容可参考 官方文档

@Cacheable 中 condition 的进一步说明

有的时候我们可能并不希望缓存一个方法所有的返回结果。通过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;
}

@CachePut

@CachePut:配置于函数上,能够根据参数定义条件来进行缓存,它与@Cacheable不同的是,它每次都会真是调用函数,所以主要用于数据新增和修改操作上。

它的参数与@Cacheable类似,具体功能可参考上面对@Cacheable参数的解析

@Cacheable 与 @CachePut 的区别

  • 在支持Spring Cache的环境下,对于使用@Cacheable标注的方法,Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素,如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,否则才会执行并将返回结果存入指定的缓存中。

  • 与@Cacheable不同的是使用@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。

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

@CacheEvict

@CacheEvict是用来标注在需要清除缓存元素的方法或类上的。当标记在一个类上时表示其中所有的方法的执行都会触发缓存的清除操作。
除了同@Cacheable一样的参数之外,它还有下面两个参数:

  • allEntries:非必需,默认为false。当为true时,会移除所有数据
  • beforeInvocation:非必需,默认为false,会在调用方法之后移除数据。当为true时,会在调用方法之前移除数据。

未完, 待续

~ end

正文到此结束
广告是为了更好的提供数据服务
本文目录