第九章:(2)Spring Boot 与 缓存 之 @Cacheable 注解

一、@Cacheable 注解

  作用:将方法的运行结果进行缓存,以后再要相同的数据,直接从缓存中获取,不用调用方法:

  属性:

value/cacheNames:指定缓存组件的名字;
  CacheManager 管理多个 Cache 组件,对缓存的真正CRUD操作在Cache组件中,每一个缓存组件有自己唯一一个名字

key: 缓存数据使用的 key,可以用它来指定。默认是使用方法参数的值。如 id=1, 1——>方法的返回值
   使用SPEL表达式:#id 是参数 id 的值 #a0 #p0 #root.arg[0]

keyGenerator:key 的生成器,可以自己指定 key 的生成器的组件 id
  key 与 keyGenerator 二选一使用

cacheManager:指定缓存管理器;或者是 cacheResolver

condition:判断条件,指定符合条件的情况下才缓存

unless:否定,unless 指定的条件为 true,方法的返回值就不会被缓存,可以获取到结果进行判断
	  unless = "#result == null"

sync:是否使用异步模式

  

  代码示例:

@Cacheable(cacheNames = {"emp"})
public Employee getEmpById(Integer id) {
    System.out.println("查询" + id +"号员工");
    return employeeMapper.getEmpById(id);
}

二、@Cacheable 原理

  当在主程序类上使用了 @EnableCaching 注解就可以开启基于注解的缓存,下面来分析一下缓存的原理。

  1、自动配置类 CacheAutoConfiguration

    

     给容器中导入 CacheConfigurationImportSelector 类。

  2、CacheConfigurationImportSelector 给容器中导入一系列的缓存的配置类

    

     导入的自动配置类:

    

  3、查看那个配置类默认生效

    在配置文件中使用 debug = true 打开配置报告

     默认是 SimpleCacheConfiguration 缓存配置类生效。

  4、SimpleCacheConfiguration 作用

    SimpleCacheConfiguration 给容器中注册了一个CacheManager: ConcurrentMapCacheManager             

  5、ConcurrentMapCacheManager 作用

    ConcurrentMapCacheManager 实现了 CacheManager 接口,并重写了其中的方法:

    

     ConcurrentMapCacheManager 作用:

      (1)可以获取和创建 ConcurrentMapCache 类型的缓存组件;

      (2)他的作用是将数据保存到 ConcurrentMap 中;

  6、ConcurrentMapCache  类

    用于缓存数据的类,其中使用 ConcurrentMap 来缓存数据。

    

        存放值的方法:

    

       

三、运行流程

  以 @Cacheable 注解为例:

  1、方法运行之前,先去查询 Cache(缓存组件),按照 cacheNames 指定的名字获取(CacheManager先获取相应的缓存),第一次获取缓存组件如果没有 Cache 组件会自动创建;

    

  2、去 Cache 中查找缓存的内容,使用一个 key(默认就是方法的参数),key 是按照某种策略生成的 ,默认是使用  keyGenerator 生成的,默认使用         SimpleKeyGenerator 生成 key;

    SimpleKeyGenerator 生成 key 的默认策略

  如果没有参数:key = new SimpleKeyGenerator

  如果有一个参数: key = 参数的值

  如果有多个参数:key = new SimpleKey(param);

      

  3、没有查到缓存就调用目标方法;

  4、将目标方法返回的结果,放进缓存中

  @Cacheable 标注的方法执行之前先来检查缓存中有没有这个数据,默认按照参数的值作为 key 去查询,如果没有就运行方法,并将结果放入缓存中,以后再来调用就可以直接使用缓存中的数据。

 

  核心

  (1)使用 CacheManager【ConcurrentMapCacheManager】 按照名字得到 Cache 【ConcurrentMapCache】组件;

  (2)key 是使用 keyGenerator  生成的,默认是 SimpleKeyGenerator  生成的;

四、常用属性

  1、value/cacheNames

    指定缓存组件的名字;将方法的返回结果放在哪个缓存中,是数组的方式,可以指定多个缓存

    示例:

    @Cacheable(cacheNames = {"emp", "temp"})
    public Employee getEmpById(Integer id) {
        System.out.println("查询" + id +"号员工");
        return employeeMapper.getEmpById(id);
    }

  2、key: 缓存数据使用的 key

    支持使用 Spel 表达式

使用SPEL表达式:#id 是参数 id 的值 #a0 #p0 #root.arg[0]
getEmp[1] 作为 key key = "#root.methodName + '[' + #id + ']'"

    Spel 表达式:

    

  3、keyGenerator:key 的生成器

    key 与 keyGenerator 二选一使用,可以自定义keyGenerator

    自定义 KeyGenerator:

@Configuration
public class MyCacheConfig {

    @Bean(value = "myKeyGenerator")
    public KeyGenerator keyGenerator() {
        return new KeyGenerator(){
            @Override
            public Object generate(Object target, Method method, Object... params) {
                return method.getName() + "[" + Arrays.asList(params).toString() + "]";
            }
        };
    }
}

    @Cacheable(cacheNames = {"emp"}, keyGenerator = "myKeyGenerator")
    public Employee getEmpById(Integer id) {
        System.out.println("查询" + id +"号员工");
        return employeeMapper.getEmpById(id);
    }

  4、condition:判断条件,指定符合条件的情况下才缓存

condition = "#a0 > 1" 当第一个参数的值 > 1 的时候才进行缓存
condition = "#a0 > 1 and #root.methodName eq 'getEmpById'" 第一个参数的值 > 1 并且方法名是 getEmpById

  

  5、unless:否定,unless 指定的条件为 true,方法的返回值就不会被缓存,可以获取到结果进行判断

unless = "#result == null" 方法返回值如果为null,结果不缓存
unless = "#a0 == 2 " 如果第一个参数的值是2,结果不缓存

    示例:

    @Cacheable(cacheNames = {"emp"}, keyGenerator = "myKeyGenerator", condition = "#a0 > 1", unless = "#a0 == 2 ")
    public Employee getEmpById(Integer id) {
        System.out.println("查询" + id +"号员工");
        return employeeMapper.getEmpById(id);
    }

  6、sync:是否使用异步模式

    #unless()} is not supported 开启异步,不支持 unless

原文地址:https://www.cnblogs.com/niujifei/p/15730157.html