声明:Spring缓存注解的使用非常简单,主要是理解,所以本文主要以示例+注释(图片版)进行说明,核心部分
会给出文字版;当然本人测试时完整的项目代码会放在GitHub上,链接见本文末。
目录
启用Spring缓存注解技术
Spring缓存注解总体介绍
缓存注解的常用属性(以示例进行说明)
key
condition
cacheNames
unless
allEntries
beforeInvocation
缓存注解使用在返回值为viod方法上的测试
背景简述:
自Spring3.1开始,Spring就自带了对缓存的支持。我们可以直接使用Spring缓存技术将某些数据放入本机的缓存中;Spring缓存技术也可以搭配其他缓存中间件(如Redis等)进行使用,将某些数据写入到缓存中间件(缓存中间件可能在其他机器上)中。
第一步:确认Spring版本不低于3.1。
注:本人用的是SpringBoot2.1.2.RELEASE,对应的Spring版本为5.1.4.RELEASE。
第二步:在SpringBoot启动类上启用Spring缓存技术。
第三步:在类上或类中的方法上使用缓存注解。
注:这个【类】指的是注入了Spring容器中的。如果没有注入,那么在该类上或该类中的缓存注解是不会生效的。
Spring提供的缓存注解有:
常用的注解有:@EnableCaching、@Cacheable、@CacheEvict、@CachePut、@Caching、@CacheConfig。
提示:本部分提到的key,可见本文下面关于缓存注解各属性的介绍。
@EnableCaching:开关性注解,在项目启动类或某个配置类上使用此注解后,则表示允许使用注解的方式进行缓存操作,如:
@Cacheable:可用于类或方法上;在目标方法执行前,会根据key先去缓存中查询看是否有数据,有就直接
返回缓存中的key对应的value值。不再执行目标方法;无则执行目标方法,并将方法的返回值
作为value,并以键值对的形式存入缓存,如:
@CachePut:可用于类或方法上;在执行完目标方法后,并将方法的返回值作为value,并以键值对的形式存入缓存中,如:
@CacheEvict:可用于类或方法上;在执行完目标方法后,清除缓存中对应key的数据(如果缓存
中有对应key的数据缓存的话),如:
@Caching:此注解即可作为@Cacheable、@CacheEvict、@CachePut三种注解中的的任何一种或几种来使用,如:
@CacheConfig:@Cacheable、@CacheEvict、@CachePut这三个注解的cacheNames属性是必
填项(或value属性是必填项,因为value属性是cacheNames的别名属性);如果上述
三种注解都用的是同一个cacheNames的话,那么在每此都写cacheNames的话,
就会显得麻烦。如将@CacheConfig注解就是来配置一些公共属性(如:cacheNames、
keyGenerator等)的值的,如:
key的来源可分为三类,分别是:默认的、keyGenerator生成的、主动指定的。
下面在具体代码中进行说明,注意阅读注释说明!
默认key:
keyGenerator生成key:
编写配置类、定制化key生成器:
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.lang.reflect.Method;
/**
* 定制化CachingConfigurer
*
* @author JustryDeng
* @date 2019/4/11 16:26
*/
@Configuration
public class MyCachingConfigurer extends CachingConfigurerSupport {
/**
* 定制化key生成器
*
* 设置 全限定类名 + 方法名 + 参数名 共同组成 key
*
* @return key生成器
* @date 2019/4/12 14:09
*/
@Bean
@Override
public KeyGenerator keyGenerator() {
return (Object target, Method method, Object... params) -> {
StringBuilder sb = new StringBuilder(16);
sb.append(target.getClass().getName());
sb.append("_");
sb.append(method.getName());
sb.append("_");
for (int i = 0; i < params.length; i++) {
sb.append(params[i]);
if (i < params.length - 1) {
sb.append(",");
}
}
return sb.toString();
};
}
}
此时,若使用缓存注解时不指定key属性,那么就会默认采用Key生成器生成的注解:
主动指定key:
在激活注解功能前,进行condition验证,如果condition结果为true,则表明验证通过,缓存注解生效;否则缓存注解不生效。
condition作用时机在:缓存注解检查缓存中是否有对应的key-value 之前。
注:缓存注解检查缓存中是否有对应的key-value 在 运行目标方法之前,
所以 condition作用时机也在运行目标方法之前。
实验示例:
验证:
通过cacheNames对数据进行隔离,不同cacheName下可以有相同的key。也可称呼cacheName为命名空间。
下面验证的是:当同时制定多个cacheName时,从哪一个cacheName取数据。
这里先给出结论:
若属性cacheNames(或属性value)指定了多个命名空间;
当进行缓存存储时,会在这些命名空间下都存一份key-value。
当进行缓存读取时,会按照cacheNames值里命名空间的顺序,挨个挨个从命名空间中查找对应的key,如果在某个命名空间中查找打了对应的缓存,就不会再查找排在后面的命名空间,也不会再执行对应方法,直接返回缓存中的value值。
实验示例:
验证:
功能是:是否令注解(在方法执行后的功能)不生效;若unless的结果为true,则(方法执行后的功能)不生效;若unless的结果为false,则(方法执行后的)功能生效。
注:unless默认为"",即相当于默认为false。
unless的作用时机:目标方法运行后。
注:如果(因为直接从缓存中获取到了数据,而导致)目标方法没有被执行,那么unless字段不生效。
举例说明一:
对于@Cacheable注解,在执行目标方法前,如果从缓存中查询到了数据,那么直接返回缓存中的数据;如果从 缓存中没有查询到数据,那么执行目标方法,目标方法执行完毕之后,判断unless的结果,若unless的结果为true,那么不缓存方法的返回值;若unless的结果为false,那么缓存方法的返回值。
举例说明二:
对于@CachePut注解,在目标方法执行完毕之后,判断unless的结果,若unless的结果为true,那么不缓存方法的返回值;若unless的结果为false,那么缓存方法的返回值。
注:因为unless的作用时机是在方法运行完毕后,所以我们可以用SpEL表达式#result 来获取方法的返回值。
实验示例:
验证:
说明:本人跑了几次此测试方法,每次随机产生的key(从代码里面可知,本人已入参参数为key)都是之前缓存
里面没有的,也就是说每次都会执行目标方法;发现大于等于5000的随机数都存入缓存汇总了;而小
于5000的随机数则没有。
此属性主要出现在@CacheEvict注解中,表示是否清除指定命名空间中的所有数据,默认为false。
此属性主要出现在@CacheEvict注解中,表示 是否在目标方法执行前使 此注解生效。 默认为false,即:目标方法执行完毕后此注解生效。
结论是:缓存注解作用于void方法上,仍然会向缓存中进行存储,不过键值对中的value为null。
实验示例:
验证:
关于Spring缓存注解的其他一些属性、用法等这里就不再一一叙述了,感兴趣的可自行查询相关资料或阅读源码进行测试。