SpringBoot使用Spring缓存注解

声明: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)指定了多个命名空间;

 

  1. 当进行缓存存储时,会在这些命名空间下都存一份key-value。

  2. 当进行缓存读取时,会按照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

猜你喜欢

转载自blog.csdn.net/justry_deng/article/details/89283664