声明:Spring缓存注解的使用非常简单,主要是理解,所以本文主要以示例+注释(图片版)进行说明,核心部分 会给出文字版;当然本人测试时完整的项目代码会放在GitHub上,链接见本文末。
目录
启用Spring缓存注解技术
Spring缓存注解总体介绍
缓存注解的常用属性(以示例进行说明)
key
condition
cacheNames
unless
allEntries
beforeInvocation
缓存注解使用在返回值为viod方法上的测试
背景简述: 自Spring3.1开始,Spring就自带了对缓存的支持。我们可以直接使用Spring缓存技术将某些数据放入本机的缓存中;Spring缓存技术也可以搭配其他缓存中间件(如Redis等)进行使用,将某些数据写入到缓存中间件(缓存中间件可能在其他机器上)中。
启用Spring缓存注解技术: 第一步:确认Spring版本不低于3.1。
注:本人用的是SpringBoot2.1.2.RELEASE,对应的Spring版本为5.1.4.RELEASE。
第二步:在SpringBoot启动类上启用Spring缓存技术。
第三步:在类上或类中的方法上使用缓存注解。
注:这个【类】指的是注入了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: 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验证,如果condition结果为true,则表明验证通过,缓存注解生效;否则缓存注解不生效。
condition作用时机在:缓存注解检查缓存中是否有对应的key-value 之前。 注:缓存注解检查缓存中是否有对应的key-value 在 运行目标方法之前, 所以 condition作用时机也在运行目标方法之前。
实验示例:
验证:
cacheNames: 通过cacheNames对数据进行隔离,不同cacheName下可以有相同的key。也可称呼cacheName为命名空间。
下面验证的是:当同时制定多个cacheName时,从哪一个cacheName取数据。
这里先给出结论:
若属性cacheNames(或属性value)指定了多个命名空间;
当进行缓存存储时,会在这些命名空间下都存一份key-value。
当进行缓存读取时,会按照cacheNames值里命名空间的顺序,挨个挨个从命名空间中查找对应的key,如果在某个命名空间中查找打了对应的缓存,就不会再查找排在后面的命名空间,也不会再执行对应方法,直接返回缓存中的value值。
实验示例:
验证:
unless: 功能是:是否令注解(在方法执行后的功能)不生效;若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的随机数则没有。
allEntries: 此属性主要出现在@CacheEvict注解中,表示是否清除指定命名空间中的所有数据,默认为false。
beforeInvocation: 此属性主要出现在@CacheEvict注解中,表示 是否在目标方法执行前使 此注解生效。 默认为false,即:目标方法执行完毕后此注解生效。
缓存注解使用在返回值为viod方法上的测试: 结论是:缓存注解作用于void方法上,仍然会向缓存中进行存储,不过键值对中的value为null。
实验示例:
验证:
笔者寄语: 关于Spring缓存注解的其他一些属性、用法等这里就不再一一叙述了,感兴趣的可自行查询相关资料或阅读源码进行测试。
^^ 如有不当之处,欢迎指正 ^^ 测试代码托管链接 https://github.com/JustryDeng/CommonRepository ^_^ 本文已经被收录进《程序员成长笔记(五)》,笔者JustryDeng ———————————————— 版权声明:本文为CSDN博主「justry_deng」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/justry_deng/article/details/89283664
来源:oschina
链接:https://my.oschina.net/u/2963604/blog/4320869