• 002-spring cache 基于注解的缓存-01-关键注解概述、spel、缓存Key 与 缓存解析器


    一、简述

    1.1、基础概念、缓存注解

    名称 解释
    Cache   缓存接口,定义缓存操作。实现有:RedisCache、EhCacheCache、ConcurrentMapCache等
    CacheManager   缓存管理器,管理各种缓存(cache)组件
    @Cacheable 加缓存 主要针对方法配置,能够根据方法的请求参数对其进行缓存,一般放在创建和获取的方法上
    @CacheEvict 删缓存 清空缓存,用于删除的方法上
    @CachePut 重新加缓存 保证方法被调用,又希望结果被缓存。
    与@Cacheable区别在于是否每次都调用方法,常用于更新
    @EnableCaching   开启基于注解的缓存
    keyGenerator   缓存数据时key生成策略
    serialize   缓存数据时value序列化策略
    @CacheConfig   统一配置本类的缓存注解的属性,与其它缓存配合使用

    1.2、三个操作缓存注解@Cacheable/@CachePut/@CacheEvict 主要的参数

    名称解释
    value 缓存的名称,在 spring 配置文件中定义,必须指定至少一个
    例如:@Cacheable(value=”mycache”) 或者@Cacheable(value={”cache1”,”cache2”})
    key 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合
    例如:@Cacheable(value=”testcache”,key=”#id”)
    condition 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存/清除缓存
    例如:@Cacheable(value=”testcache”,condition=”#userName.length()>2”)
    unless 否定缓存。当条件结果为TRUE时,就不会缓存。
    @Cacheable(value=”testcache”,unless=”#userName.length()>2”)
    allEntries
    (@CacheEvict )
    是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存
    例如:@CachEvict(value=”testcache”,allEntries=true)
    beforeInvocation
    (@CacheEvict)
    是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存
    例如:@CachEvict(value=”testcache”,beforeInvocation=true)

    1.3、上述注解会有条件-SpEL上下文数据

      Spring Cache提供了一些供我们使用的SpEL上下文数据,下表直接摘自Spring官方文档: 

    名称位置描述示例
    methodName root对象 当前被调用的方法名 #root.methodname
    method root对象 当前被调用的方法 #root.method.name
    target root对象 当前被调用的目标对象实例 #root.target
    targetClass root对象 当前被调用的目标对象的类 #root.targetClass
    args root对象 当前被调用的方法的参数列表 #root.args[0]
    caches root对象 当前方法调用使用的缓存列表 #root.caches[0].name
    Argument Name 执行上下文 当前被调用的方法的参数,如findArtisan(Artisan artisan),可以通过#artsian.id获得参数 #artsian.id
    result 执行上下文 方法执行后的返回值(仅当方法执行后的判断有效,如 unless cacheEvict的beforeInvocation=false) #result

    注意:

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

      @Cacheable(key = "targetClass + methodName +#p0")

      2.使用方法参数时我们可以直接使用“#参数名”或者“#p参数index”。 如:

      @Cacheable(value="users", key="#id")

      @Cacheable(value="users", key="#p0")

     SpEL提供了多种运算符

    类型运算符
    关系 <,>,<=,>=,==,!=,lt,gt,le,ge,eq,ne
    算术 +,- ,* ,/,%,^
    逻辑 &&,||,!,and,or,not,between,instanceof
    条件 ?: (ternary),?: (elvis)
    正则表达式 matches
    其他类型 ?.,?[…],![…],^[…],$[…]

    二、缓存Key 与 缓存解析器

    2.1、缓存Key说明

    2.1.1、默认Key生成

      由于缓存本质上是键值存储,因此每次缓存方法的调用都需要转换为适合缓存访问的key。抽象缓存使用一个简单的基于以下算法KeyGenerator:

    如果没有给出参数,则返回SimpleKey.EMPTY。 
    如果只给出一个参数,则返回该实例。
    如果给出了多于一个参数,返回一个包含所有参数的SimpleKey。

      这种方法适用于大多数使用情况;只要参数具有自然键并实现有效的hashCode()和equals()方法。如果情况并非如此,那么战略需要改变。

      为了提供不同的默认key生成器,需要实现org.springframework.cache.interceptor.KeyGenerator接口。

      注意:默认的key生成策略随着Spring 4.0的发布而改变。 Spring的早期版本使用了一种key生成策略,对于多个关键参数,只考虑参数的hashCode()而不考虑equals();这可能会导致意外的键碰撞(请参阅SPR-10237的背景)。新的'SimpleKeyGenerator'使用复合键来实现这种场景。

      如果您想继续使用以前的key策略,则可以配置弃用的org.springframework.cache.interceptor.DefaultKeyGenerator类或创建基于散列的自定义“KeyGenerator”实现。

    2.1.2、自定义key生成策略

      由于缓存是通用的,因此目标方法很可能具有不能简单映射到缓存结构顶部的各种签名。当目标方法有多个参数,其中只有一些适用于缓存(而其余的仅由方法逻辑使用)时,这会变得很明显。例如:

    @Cacheable("books")
    public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

      对于这种情况,@Cacheable注解允许用户指定如何通过其关键属性生成key。开发人员可以使用SpEL来选择感兴趣的参数(或它们的嵌套属性),执行操作甚至调用任意方法,而无需编写任何代码或实现任何接口。这是对默认生成器的推荐方法,因为方法与代码库增长的方式在签名方面往往有很大不同;而默认策略可能适用于某些方法,但对于所有方法都很少。

    @Cacheable(cacheNames="books", key="#isbn")
    public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
    
    @Cacheable(cacheNames="books", key="#isbn.rawNumber")
    public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
    
    @Cacheable(cacheNames="books", key="T(someType).hash(#isbn)")
    public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

      上面的代码片段显示了选择某个参数,它的一个属性,甚至是一个任意的(静态)方法是多么简单。

      如果负责生成key的算法过于具体或者需要共享,您可以在操作中定义一个自定义keyGenerator。为此,请指定要使用的KeyGenerator bean实现的名称:

    @Cacheable(cacheNames="books", keyGenerator="myKeyGenerator")
    public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

      注意:key和keyGenerator参数是互斥的,指定两者的操作将导致异常。

    2.2、缓存解析器

    2.2.1、默认缓存解析器

      缓存抽象使用一个简单的CacheResolver,它使用配置的CacheManager检索在操作级别定义的缓存。

      要提供不同的默认缓存解析器,需要实现org.springframework.cache.interceptor.CacheResolver接口。

    2.2.2、自定义缓存解析器

      默认的缓存解析非常适合使用单个CacheManager并且不需要复杂的缓存解析要求的应用程序。对于使用多个缓存管理器的应用程序,可以将cacheManager设置为使用每个操作:

    @Cacheable(cacheNames="books", cacheManager="anotherCacheManager")
    public Book findBook(ISBN isbn) {...}

      也可以完全以与key生成类似的方式替换CacheResolver。该解决方案针对每个缓存操作进行请求,给予实现基于运行时参数实际解析要使用的缓存的机会:

    @Cacheable(cacheResolver="runtimeCacheResolver")
    public Book findBook(ISBN isbn) {...}

      注意:自Spring 4.1以来,缓存注释的值属性不再是强制性的,因为无论注释的内容如何,​​CacheResolver都可以提供此特定信息。

      与key和keyGenerator类似,cacheManager和cacheResolver参数是互斥的,指定两者的操作将导致出现异常,因为CacheResolver实现将忽略自定义CacheManager。这可能不是你所期望的。

     

     
  • 相关阅读:
    【小工具】根据定义的白名单字段进行Bean的拷贝
    【Java】Java8的Lambda入门记录
    【Java】浅谈Java IO
    【工具】我的Git学习日志
    【Java】浅谈HashMap
    【Java】Java Queue的简介
    【ZooKeeper】ZooKeeper入门流水记
    【MQTT】Mosquitto的安装与使用流水记
    【数据结构】简单的数据结构图解
    【Java多线程】JDK1.5并发包API杂谈
  • 原文地址:https://www.cnblogs.com/bjlhx/p/9167210.html
Copyright © 2020-2023  润新知