# gallop-cache-spring-boot-starter **Repository Path**: gallop-project/gallop-cache-spring-boot-starter ## Basic Information - **Project Name**: gallop-cache-spring-boot-starter - **Description**: 为微服务构建提供分布式缓存/锁支持 - **Primary Language**: Java - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2022-10-27 - **Last Updated**: 2023-04-11 ## Categories & Tags **Categories**: Uncategorized **Tags**: SpringCloud, SpringBoot, Lock, Cache ## README # gallop-cache-spring-boot-starter `SpringBoot`/`SpringCloud`构建微服务所需`分布式缓存`和`分布式锁`的一种实现。 ## TODO * lock 增加返回值 ## 引入 * `maven repo`: (还未上传) * 拷贝工程到本地-> `mvn install` 或 加入自己的工程; * 配置: ```yml # 以application.yml为例 gallop: cache: # 设置默认的缓存策略执行器。支持nop/redis/memory,配置不存在时使用nop executor-strategy: redis # 默认的延迟双删时间间隔(毫秒)。配置不存在时使用默认值2000 delay-removal-millis: 5000 # 缓存策略需要redis连接 spring: redis: host: 127.0.0.1 port: 6379 password: foobar ``` ## 分布式缓存 ### 如何使用 #### 例1 注解方式查询并缓存: ```java // 查询+加载 import com.gallop.common.cache.CacheQuery; import com.gallop.common.cache.CacheQueryConstants; import com.gallop.common.cache.CacheQueryKey; import org.springframework.stereotype.Service; import java.util.concurrent.TimeUnit; @Service public class FooBarServiceImpl implements FooService { // 其他代码略... @CacheQuery( primaryKey = "TEST_CACHE_PRIMARY_KEY", expireAfter = 10, expireTimeUnit = TimeUnit.SECONDS, cacheStrategy = CacheQueryConstants.ExecutorStrategy.REDIS ) public FooBean queryFooByProp(@CacheQueryKey String prop1) { return xxxx; } } ``` 上述代码定义了一个会使用缓存的查询方法`queryFooByProp`,如果方法以如下方式调用: ```java fooBarService.queryFooByProp("abcd"); ``` 此时,缓存检查会代替方法本身被优先触发。同时注意到缓存策略为`REDIS`,程序会使用键: ```java "TEST_CACHE_PRIMARY_KEY:abcd" ``` 来查询redis,如果找到了未过期的缓存值,此方法调用会直接返回;否则执行方法本身,返回值以同样的键加入缓存,并设置`10秒`的有效期。 #### 例2 删除缓存: ```java // 缓存设置失效 import com.gallop.common.cache.CacheExecutor; import com.gallop.common.cache.CacheQueryConstants; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class FooBarServiceImpl implements FooService { // 其他代码略... @Autowired private CacheExecutor cacheExecutor; public Boolean removeFoo(FooBean fooBean) { // 数据本身的删除 removeById(fooBean.getId()); // 删除缓存 cacheExecutor.removeCache("TEST_CACHE_PRIMARY_KEY", fooBean.getProp1()); // 另: 删除缓存,并使用默认时间间隔延迟再次执行一次删除操作 cacheExecutor.removeCacheWithDelay("TEST_CACHE_PRIMARY_KEY", fooBean.getProp1()); } } ``` 上述代码中给出了删除缓存的示例(`CacheExecutor`提供了针对缓存的插入,查询,删除等全部操作,并提供多种重载,实际上`@CacheQuery`注解只是调用这些方法的其中一种方式)。 `CacheExecutor`可直接注入bean中,默认对应配置`gallop.cache.executor-strategy`设置的执行器。 如果想使用其他自定义执行器,可直接注入相关执行器引用。当前支持的缓存策略执行器有: | 执行器 | 对应枚举 | 引用示例 | |----------------------------------|--------------------------------------------|----------------------------------------------------| | NopCacheExecutor(缺省无操作实现) | CacheQueryConstants.ExecutorStrategy.NOP | @Autowired private NopCacheExecutor executor; | | InMemoryCacheExecutor(单机场景实现) | CacheQueryConstants.ExecutorStrategy.MEMORY | @Autowired private InMemoryCacheExecutor executor; | | RedissonCacheExecutor(分布式场景主要实现) | CacheQueryConstants.ExecutorStrategy.REDIS | @Autowired private RedissonCacheExecutor executor; | | 配置文件决定的默认执行器(未配置时为NOP) | CacheQueryConstants.ExecutorStrategy.DEFAULT | @Autowired private CacheExecutor executor; | #### 说明: * 工作原理:当调用方法`queryFooByProp`会使用缓存框架,按照查询缓存-> 加载并缓存的逻辑执行。 当缓存命中时,不会调用方法本身(缓存直接返回);否则执行方法并把返回结果加入缓存; * 缓存key: 用于唯一确定一个缓存。 由`主键`+`参数列表`拼接构成,`主键`在`@CacheQuery`中定义, `参数列表`在方法参数列表中通过`@CacheQueryKey`声明,可声明0个或多个(`needParam`控制)。 #### 注意: * **使用缓存的方法必须有返回值!** * **`@CacheQuery`暂不支持加在接口方法上!** * 因为`spring aop`的触发机制,同一类中`this.xxx(foo,bar)`方式调用缓存修饰方法会导致注解失效。 请确保`@CacheQuery`注解修饰的方法能够被正确触发。 (临时方案:注入自身引用并使用@Lazy修饰,通过注入的引用调用自己;后续考虑使用动态代理解决此问题) ### 参数解释: #### `CacheQuery`: | 参数 | 说明 | 备注 | |-----------------|--------------------------------------------------------------|-------------------------------------------------------------------------------| | primaryKey | 保存缓存所使用的的主键 | 自定义的字符串常量; primaryKey 和 value 二者选一,优先使用primaryKey | | value | 保存缓存所使用的的主键(内置枚举类型) | `CacheQueryConstants.PrimaryKey`枚举变量 ; primaryKey 和 value 二者选一,优先使用primaryKey | | expireAfter | 缓存有效期 | | | expireTimeUnit | 缓存有效期时间单位 | 默认秒 | | cacheStrategy | 缓存执行器选择(内存/redis/无) | 默认使用配置`gallop.cache.executor-strategy`指定的类型,未指定时使用`NOP` | | cacheNullValue | 是否缓存`null`值 | 默认`false` | | needParam | 缓存key是否拼接方法参数(参数列表中@CacheQueryKey修饰的参数) | 默认`true`。 主键和参数列表一起参与缓存key的构造, 如果为`true`时方法参数中没有发现`CacheQueryKey`修饰的参数,缓存将会失效 | | assembleHandler | 主键和参数列表的拼接方式 | 默认格式为 `主键:参数1:参数2:...` ,可通过实现接口的bean自行定义 | | updateOption | 缓存更新策略 | 默认不触发。`PREDICATE`模式下,即使缓存命中还要判断一次是否查询新值替换缓存。 | | updatePredicate | 缓存更新策略执行器Class,需要是一个spring-bean,只在updateOption=PREDICATE模式下有效 | 在注解中提供bean的class或在方法列表中以参数形式提供bean,两种方式均可 | #### `CacheQueryKey`: * 使用场景: 参与缓存key拼接的**方法参数**使用此注解。加在`@CacheQuery`修饰的方法参数上; * 拼接方式: 使用默认的参数拼接器时,所有参数会通过`toString`方法转字符串,并通过`:`连接; 最后和`主键`连接在一起。例: `FOO_BAR_PK:arg1:arg2`;当`@CacheQuery#needParam`设置`false`时, 只使用`主键`作为缓存key,忽略参数; * 支持类型: 理论上支持所有的参数类型,但其中几种特殊情况如下: | 类型 | 转换方法 | |------------------------|--------------------------------| | 枚举类 | 使用`name()`转字符串 | | AssembleKeyParameter接口 | 使用`toKey()`转字符串,支持更多的自定义参数转换场景 | #### `CacheExecutor`: * 说明: * api: #### `CacheKeyAssembleHandler`: * 说明: * 默认实现: * 自定义: #### `UpdateOption` 和 `CacheUpdatePredicate`: * 使用场景: * 自定义: ## 分布式锁