Appearance
acuity-cache-starter缓存处理类
天源云的key命名规则
WARNING
规定了key的命名规则为:[前缀]:[租户ID]:[服务模块名:]业务类型:[业务字段]:[value类型]:[业务值]
例如: lc:1:base:base_dict: id:String:BASE_ORG_TYPE
lc(老崔)前缀:1是企业id:base是基础模块:字典表名:id字段:id类型是string:字典键值
本模块将
分布式缓存redis
和内存缓存caffeine
的一些基础共有方法抽象出来,达到平滑切换缓存的目的。业务系统使用时,注入 CacheOps 类即可。但这样做又有几个缺陷: redis 的一些特殊方法将无法使用 list、set、hash 高级功能, 因此特意新增加一个 CacheOpsPlus 类支持 redis 全部接口。
建议
在 caffeine 实现是为了解决开发环境没有部署 redis 时应急使用, 生产环境请使用 redis 实现.
使用 acuity-cache-starter 后想用 redis 的 特殊方法 怎么用?
配置文件配置 acuity.cache.type=redis 后,注入 CacheOpsPlus 即可, 只要你能保证系统必须依赖 redis 即可。 但 CacheOpsPlus 基于内存等实现不能保证代码的正确性!!! (开发环境没有部署 redis 时,将配置调整成 caffeine 应急使用)
为啥要在封装一次?
- 项目比较小(基本都是 CRUD 功能),而且团队中会优雅使用 redis 的比较少,而且会频繁的复制代码到 N 个项目,每个项目随时都可能会重新部署或者迁移一套环境用于演示,这里就是想让一些部署去演示的项目,直接用内存缓存即可,少部署一个 redis。
- 开发电脑配置比较低,启动太多中间件会很卡,对于专心编码的开发来说,少启动一个中间件,对开发的体验比较好
- 本地没有部署 redis, 又无测试 redis 环境可用, 基于启动项目开发功能, 将配置调整成 caffeine 即可
本模块核心 API
- CacheOps : 基础缓存操作类
- CachePlusOps : 增强缓存操作类, 包含了 redis 常用的方法
- CacheKey (为了解耦, 已经移动到你 acuity-core 模块下) : 封装了缓存 key 和 过期时间的 缓存 Key 对象
- RedisDistributedLock : 分布式锁的简单实现
注意事项
- 本模块虽然实现了 SpringCache 管理器重写, 但不建议在项目中使用. (原因: this 调用时, @Cache 不生效)
- CAFFEINE 模式
请勿在生产使用
, 仅仅支持本地环境没有 redis 环境时,应急使用. - 通过
acuity.cache.cacheNullVal
全局配置是否缓存空值 - 通过
acuity.cache.serializerType
配置 redis 类型的缓存序列化的方式。 (注意,修改序列化类型后,需要先清空 redis 的所有缓存,并重启项目。 生产环境请勿轻易、经常切换序列化类型!)
yaml
acuity:
cache:
type: REDIS
cacheNullVal: true #是否缓存空值
serializerType: ProtoStuff # 序列化类型 支持:JACK_SON、ProtoStuff、JDK
# def: # 不推荐使用。 用来配置Spring提供的@Cache的,自行阅读源码
# configs: # 不推荐使用。 用来配置Spring提供的@Cache的,自行阅读源码
acuity:
cache:
type: REDIS
cacheNullVal: true #是否缓存空值
serializerType: ProtoStuff # 序列化类型 支持:JACK_SON、ProtoStuff、JDK
# def: # 不推荐使用。 用来配置Spring提供的@Cache的,自行阅读源码
# configs: # 不推荐使用。 用来配置Spring提供的@Cache的,自行阅读源码
- serializerType 使用 JACK_SON 类型时,直接存储 Long 类型的值,从 redis 中取出数据时,需要手动强制转换成 Long 才行,否则会报错!!!
- acuity-cloud 不能使用内存缓存,否则无法登录
如何新项目如何接入
1, 在 pom.xml 中加依赖
xml
<dependency>
<groupId>top.acuity.commons</groupId>
<artifactId>acuity-cache-starter</artifactId>
</dependency>
<dependency>
<groupId>top.acuity.commons</groupId>
<artifactId>acuity-cache-starter</artifactId>
</dependency>
- 在 redis.yml 中加入配置
yaml
acuity:
redis:
ip: 127.0.0.1
port: 16379
password: 12345678
database: 0
cache:
type: REDIS # CAFFEINE
cacheNullVal: true # 是否缓存null值
serializerType: ProtoStuff # 序列化类型 支持:JACK_SON、ProtoStuff、JDK
spring:
redis:
host: ${acuity.redis.ip}
password: ${acuity.redis.password}
port: ${acuity.redis.port}
database: ${acuity.redis.database}
acuity:
redis:
ip: 127.0.0.1
port: 16379
password: 12345678
database: 0
cache:
type: REDIS # CAFFEINE
cacheNullVal: true # 是否缓存null值
serializerType: ProtoStuff # 序列化类型 支持:JACK_SON、ProtoStuff、JDK
spring:
redis:
host: ${acuity.redis.ip}
password: ${acuity.redis.password}
port: ${acuity.redis.port}
database: ${acuity.redis.database}
- 若缓存想使用 CAFFEINE 模式, 需要在依赖中排除 redis
xml
<dependency>
<groupId>top.acuity.commons</groupId>
<artifactId>acuity-cache-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>top.acuity.commons</groupId>
<artifactId>acuity-cache-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</exclusion>
</exclusions>
</dependency>
- 为需要缓存的数据创建 CacheKeyBuilder ,如
ApplicationCacheKeyBuilder
java
public class ApplicationCacheKeyBuilder implements CacheKeyBuilder {
@Override
public String getPrefix() {
return CacheKeyDefinition.APPLICATION; //key前缀
}
@Override
public Duration getExpire() {
return Duration.ofHours(24); // 有效期
}
}
public class ApplicationCacheKeyBuilder implements CacheKeyBuilder {
@Override
public String getPrefix() {
return CacheKeyDefinition.APPLICATION; //key前缀
}
@Override
public Duration getExpire() {
return Duration.ofHours(24); // 有效期
}
}
- 需要操作缓存的地方注入 CacheOps
java
@Autowired // 普通缓存功能
private CacheOps cacheOps;
@Autowired // 增强功能
private CachePlusOps cachePlusOps;
public void teset(){
CacheKey cacheKey = new VerificationCodeCacheKeyBuilder().key(data.getType().name(), data.getMobile());
cacheOps.set(cacheKey, code);
}
@Autowired // 普通缓存功能
private CacheOps cacheOps;
@Autowired // 增强功能
private CachePlusOps cachePlusOps;
public void teset(){
CacheKey cacheKey = new VerificationCodeCacheKeyBuilder().key(data.getType().name(), data.getMobile());
cacheOps.set(cacheKey, code);
}
原理
为什么在 pom 中引入依赖 acuity-cache-starter
后,在项目中就能注入使用了?
java
@Autowired
private CacheOps cacheOps;
@Autowired
private CacheOpsPlus cacheOpsPlus;
@Autowired
private CacheOps cacheOps;
@Autowired
private CacheOpsPlus cacheOpsPlus;
1, acuity-cache-starter/src/main/resources/META-INF/spring.factories
中有如下配置,该配置会在项目启动时,自动加载 CacheAutoConfigure 类。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
top.acuity.commons.cache.CacheAutoConfigure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
top.acuity.commons.cache.CacheAutoConfigure
2, 这个类通过注解启用了缓存, 并导入 Caffeine 自动配置类和 Redis 自动配置类
java
@EnableCaching
@Import({
CaffeineAutoConfigure.class, RedisAutoConfigure.class
})
public class CacheAutoConfigure {
//省略...
}
@EnableCaching
@Import({
CaffeineAutoConfigure.class, RedisAutoConfigure.class
})
public class CacheAutoConfigure {
//省略...
}
3,CaffeineAutoConfigure 会读取 yml 里面的配置, 当 acuity.cache.type=CAFFEINE 时生效,CaffeineAutoConfigure 类内部实例化了 CaffeineOpsImpl。 RedisAutoConfigure 在 acuity.cache.type=REDIS 时生效,acuity.cache.type 没有配置时,默认使用 redis 的配置,RedisAutoConfigure 内部实例化了 RedisOpsImpl。
所以,在项目中注入 CacheOps 或者 CacheOpsPlus 即可。
java
@Slf4j
@ConditionalOnProperty(name = "acuity.cache.type", havingValue = "CAFFEINE")
@EnableConfigurationProperties({CustomCacheProperties.class})
public class CaffeineAutoConfigure {
@Bean
@ConditionalOnMissingBean
public CacheOps cacheOps() {
return new CaffeineOpsImpl();
}
@Bean
@ConditionalOnMissingBean
public CachePlusOps cachePlusOps() {
return new CaffeineOpsImpl();
}
}
@ConditionalOnClass(RedisConnectionFactory.class)
@ConditionalOnProperty(name = "acuity.cache.type", havingValue = "REDIS", matchIfMissing = true)
@EnableConfigurationProperties({RedisProperties.class, CustomCacheProperties.class})
public class RedisAutoConfigure {
@Bean
@ConditionalOnMissingBean
public CacheOps cacheOps(RedisOps redisOps) {
return new RedisOpsImpl(redisOps);
}
@Bean
@ConditionalOnMissingBean
public CachePlusOps cachePlusOps(RedisOps redisOps) {
return new RedisOpsImpl(redisOps);
}
}
@Slf4j
@ConditionalOnProperty(name = "acuity.cache.type", havingValue = "CAFFEINE")
@EnableConfigurationProperties({CustomCacheProperties.class})
public class CaffeineAutoConfigure {
@Bean
@ConditionalOnMissingBean
public CacheOps cacheOps() {
return new CaffeineOpsImpl();
}
@Bean
@ConditionalOnMissingBean
public CachePlusOps cachePlusOps() {
return new CaffeineOpsImpl();
}
}
@ConditionalOnClass(RedisConnectionFactory.class)
@ConditionalOnProperty(name = "acuity.cache.type", havingValue = "REDIS", matchIfMissing = true)
@EnableConfigurationProperties({RedisProperties.class, CustomCacheProperties.class})
public class RedisAutoConfigure {
@Bean
@ConditionalOnMissingBean
public CacheOps cacheOps(RedisOps redisOps) {
return new RedisOpsImpl(redisOps);
}
@Bean
@ConditionalOnMissingBean
public CachePlusOps cachePlusOps(RedisOps redisOps) {
return new RedisOpsImpl(redisOps);
}
}
缓存的Key
CacheKey
k-v类型缓存的key,封装缓存的key和key的有效期。
CacheHashKey
hash类型缓存的key,封装缓存的key、field以及key的有效期。
CacheKeyBuilder
key的构造器,用来生成key并构造CacheKey。生成key的规则如下
java
/**
* 根据动态参数 拼接key
* <p>
* key命名规范:[租户编码:][服务模块名:]业务类型[:业务字段][:value类型][:业务值]
*
* @param uniques 动态参数
* @return
*/
default String getKey(Object... uniques) {
ArrayList<String> regionList = new ArrayList<>();
String prefix = this.getPrefix();
if (StrUtil.isNotEmpty(prefix)) {
regionList.add(prefix);
}
String tenant = this.getTenant();
// 租户编码:存储默认库的全局缓存,可以重写getTenant并返回null
if (StrUtil.isNotEmpty(tenant)) {
regionList.add(tenant);
}
// 服务模块名
String modular = getModular();
if (StrUtil.isNotEmpty(modular)) {
regionList.add(modular);
}
// 业务类型
String table = this.getTable();
ArgumentAssert.notEmpty(table, "缓存业务类型不能为空");
regionList.add(table);
// 业务字段
String field = getField();
if (StrUtil.isNotEmpty(field)) {
regionList.add(field);
}
// value类型
ValueType valueType = getValueType();
if (valueType != null) {
regionList.add(valueType.name());
}
// 业务值
for (Object unique : uniques) {
if (ObjectUtil.isNotEmpty(unique)) {
regionList.add(String.valueOf(unique));
}
}
return CollUtil.join(regionList, StrPool.COLON);
}
/**
* 根据动态参数 拼接key
* <p>
* key命名规范:[租户编码:][服务模块名:]业务类型[:业务字段][:value类型][:业务值]
*
* @param uniques 动态参数
* @return
*/
default String getKey(Object... uniques) {
ArrayList<String> regionList = new ArrayList<>();
String prefix = this.getPrefix();
if (StrUtil.isNotEmpty(prefix)) {
regionList.add(prefix);
}
String tenant = this.getTenant();
// 租户编码:存储默认库的全局缓存,可以重写getTenant并返回null
if (StrUtil.isNotEmpty(tenant)) {
regionList.add(tenant);
}
// 服务模块名
String modular = getModular();
if (StrUtil.isNotEmpty(modular)) {
regionList.add(modular);
}
// 业务类型
String table = this.getTable();
ArgumentAssert.notEmpty(table, "缓存业务类型不能为空");
regionList.add(table);
// 业务字段
String field = getField();
if (StrUtil.isNotEmpty(field)) {
regionList.add(field);
}
// value类型
ValueType valueType = getValueType();
if (valueType != null) {
regionList.add(valueType.name());
}
// 业务值
for (Object unique : uniques) {
if (ObjectUtil.isNotEmpty(unique)) {
regionList.add(String.valueOf(unique));
}
}
return CollUtil.join(regionList, StrPool.COLON);
}
Key的命名规则
阿里开发手册中,key命名风格:
- Redis key命名需具有可读性以及可管理性,不该使用含义不清的key以及特别长的key名;
- 以英文字母开头,命名中只能出现小写字母、数字、英文点号(.)和英文半角冒号( :;
- 不要包含特殊字符,如下划线、空格、换行、单双引号以及其他转义字符;
天源云的key命名规则
规定了key的命名规则为:
[前缀:][租户ID:][服务模块名:]业务类型[:业务字段][:value类型][:业务值]
前缀
可选。 用来区分不同项目或不同环境。 如:区分acuity-cloud 或 acuity-boot、acuity-cloud的dev、test或pro环境
租户ID
可选。 用来区分不同租户数据缓存。 如: 租户A和租户B分别取ContextUtil.getTenantId()中的值来区分。 若某个缓存需要无需区分租户,可以不设置租户ID
服务模块名
可选。 用来区分不同服务或功能模块的缓存。 如: 仅在base服务使用和仅在system服务使用的缓存分别用base和system来区分,多个服务共用的缓存可以不设置或者设置为common。
业务类型
必填。 用来区分不同业务类型的数据,建议设置为表名。 当同一key涉及多个业务时, 可以使用英文半角点号 (.)分割,用来表示一个完整的语义。如: lc:1:base:user.activity:id.id:number:1.1 -> [奖品id1、奖品id2] 租户ID=1,base服务,用户ID=1,活动ID=1的奖品为奖品1(数字类型)、奖品2 lc:2:base:user.activity:id.id:obj:1.2 -> [奖品id1、奖品id2] 租户ID=2,base服务,用户ID=1,活动ID=2的奖品为奖品1(数字类型)、奖品2
业务字段
可选。用来区分key通过那个字段来区分,通常设置为字段名。 当同一key涉及多个业务时, 可以使用英文半角点号 (.)分割,用来对应不同业务类型的字段。如:业务类型为 user.activity 表示用户的活动,则应该用 id.id 跟 user.activity 对应,表示key中包user的id 和 activity的id
value类型
可选。 用来区分value存储的是完整对象、数字还是字符串。Redis key命名包含key所代表的value类型,以提高可读性。如: obj 表示value存储对象,number表示value存储数字, string 表示value存储字符串。
业务值
可选。 用来区分同一业务类型的不同行的数据缓存。如: 用户表id为1和i2的缓存,分别将该值设置为1和2。
Key的定义
- CacheKey
封装redis中String、List、Set等类型的key和过期时间
- CacheHashKey
封装redis中Hash类型的key、field和过期时间
java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CacheKey {
/**
* redis key
*/
@NonNull
private String key;
/**
* 超时时间 秒
*/
private Duration expire;
public CacheKey(final @NonNull String key) {
this.key = key;
}
@Override
public String toString() {
return "key=" + key + " , expire=" + expire;
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CacheKey {
/**
* redis key
*/
@NonNull
private String key;
/**
* 超时时间 秒
*/
private Duration expire;
public CacheKey(final @NonNull String key) {
this.key = key;
}
@Override
public String toString() {
return "key=" + key + " , expire=" + expire;
}
}
java
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
public class CacheHashKey extends CacheKey {
/**
* redis hash field
*/
private Object field;
public CacheHashKey(@NonNull String key, final Object field) {
super(key);
this.field = field;
}
public CacheHashKey(@NonNull String key, final Object field, Duration expire) {
super(key, expire);
this.field = field;
}
public CacheKey tran() {
return new CacheKey(StrUtil.join(StrPool.COLON, getKey(), getField()), getExpire());
}
}
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
public class CacheHashKey extends CacheKey {
/**
* redis hash field
*/
private Object field;
public CacheHashKey(@NonNull String key, final Object field) {
super(key);
this.field = field;
}
public CacheHashKey(@NonNull String key, final Object field, Duration expire) {
super(key, expire);
this.field = field;
}
public CacheKey tran() {
return new CacheKey(StrUtil.join(StrPool.COLON, getKey(), getField()), getExpire());
}
}
如何使用
提示
如果你觉得key的命名过长,完全可以将非必填的部分置空,通过CacheKeyBuilder#getKey方法生成出来的key就会短一些。
操作缓存步骤如下:
- 定义缓存Key构造器:CacheKeyBuilder
构造器
Key构造器,又名CacheKeyBuilder。为了方便生成CacheKey,可以使用CacheKeyBuilder来构造CacheKey。
java
@FunctionalInterface
public interface CacheKeyBuilder {
/**
* 缓存前缀,用于区分项目,环境等等
*
* @return 缓存前缀
*/
default String getPrefix() {
return null;
}
/**
* 租户编码,用于区分租户
* <p>
* 非租户模式设置成空字符串
*
* @return 租户编码
*/
default String getTenant() {
return ContextUtil.getTenantId() != null ? String.valueOf(ContextUtil.getTenantId()) : null;
}
/**
* 设置企业id
*
* @param tenantId 企业id
* @return
*/
default CacheKeyBuilder setTenantId(Long tenantId) {
return this;
}
/**
* 服务模块名,用于区分后端服务、前端模块等
*
* @return 服务模块名
*/
default String getModular() {
return null;
}
/**
* key的业务类型, 用于区分表
*
* @return 通常是表名
*/
@NonNull
String getTable();
/**
* key的字段名, 用于区分字段
*
* @return 通常是key的字段名
*/
default String getField() {
return null;
}
/**
* 缓存的value存储的类型
*
* @return value类型
*/
default ValueType getValueType() {
return ValueType.obj;
}
/**
* 缓存自动过期时间
*
* @return 缓存自动过期时间
*/
@Nullable
default Duration getExpire() {
return null;
}
/**
* 获取通配符
*
* @return key 前缀
*/
default String getPattern() {
return StrUtil.format("*:{}:*", getTable());
}
/**
* 构建通用KV模式 的 cache key
* 兼容 redis caffeine
*
* @param uniques 参数
* @return cache key
*/
default CacheKey key(Object... uniques) {
String key = getKey(uniques);
ArgumentAssert.notEmpty(key, "key 不能为空");
return new CacheKey(key, getExpire());
}
/**
* 构建 redis 类型的 hash cache key
*
* @param field field
* @param uniques 动态参数
* @return cache key
*/
default CacheHashKey hashFieldKey(@NonNull Object field, Object... uniques) {
String key = getKey(uniques);
ArgumentAssert.notEmpty(key, "key 不能为空");
ArgumentAssert.notNull(field, "field 不能为空");
return new CacheHashKey(key, field, getExpire());
}
/**
* 构建 redis 类型的 hash cache key (无field)
*
* @param uniques 动态参数
* @return
*/
default CacheHashKey hashKey(Object... uniques) {
String key = getKey(uniques);
ArgumentAssert.notEmpty(key, "key 不能为空");
return new CacheHashKey(key, null, getExpire());
}
/**
* 根据动态参数 拼接key
* <p>
* key命名规范:[前缀:][租户ID:][服务模块名:]业务类型[:业务字段][:value类型][:业务值]
*
* @param uniques 动态参数
* @return
*/
default String getKey(Object... uniques) {
ArrayList<String> regionList = new ArrayList<>();
String prefix = this.getPrefix();
if (StrUtil.isNotEmpty(prefix)) {
regionList.add(prefix);
}
String tenant = this.getTenant();
// 租户编码:存储默认库的全局缓存,可以重写getTenant并返回null
if (StrUtil.isNotEmpty(tenant)) {
regionList.add(tenant);
}
// 服务模块名
String modular = getModular();
if (StrUtil.isNotEmpty(modular)) {
regionList.add(modular);
}
// 业务类型
String table = this.getTable();
ArgumentAssert.notEmpty(table, "缓存业务类型不能为空");
regionList.add(table);
// 业务字段
String field = getField();
if (StrUtil.isNotEmpty(field)) {
regionList.add(field);
}
// value类型
ValueType valueType = getValueType();
if (valueType != null) {
regionList.add(valueType.name());
}
// 业务值
for (Object unique : uniques) {
if (ObjectUtil.isNotEmpty(unique)) {
regionList.add(String.valueOf(unique));
}
}
return CollUtil.join(regionList, StrPool.COLON);
}
enum ValueType {
obj, string, number,
}
}
@FunctionalInterface
public interface CacheKeyBuilder {
/**
* 缓存前缀,用于区分项目,环境等等
*
* @return 缓存前缀
*/
default String getPrefix() {
return null;
}
/**
* 租户编码,用于区分租户
* <p>
* 非租户模式设置成空字符串
*
* @return 租户编码
*/
default String getTenant() {
return ContextUtil.getTenantId() != null ? String.valueOf(ContextUtil.getTenantId()) : null;
}
/**
* 设置企业id
*
* @param tenantId 企业id
* @return
*/
default CacheKeyBuilder setTenantId(Long tenantId) {
return this;
}
/**
* 服务模块名,用于区分后端服务、前端模块等
*
* @return 服务模块名
*/
default String getModular() {
return null;
}
/**
* key的业务类型, 用于区分表
*
* @return 通常是表名
*/
@NonNull
String getTable();
/**
* key的字段名, 用于区分字段
*
* @return 通常是key的字段名
*/
default String getField() {
return null;
}
/**
* 缓存的value存储的类型
*
* @return value类型
*/
default ValueType getValueType() {
return ValueType.obj;
}
/**
* 缓存自动过期时间
*
* @return 缓存自动过期时间
*/
@Nullable
default Duration getExpire() {
return null;
}
/**
* 获取通配符
*
* @return key 前缀
*/
default String getPattern() {
return StrUtil.format("*:{}:*", getTable());
}
/**
* 构建通用KV模式 的 cache key
* 兼容 redis caffeine
*
* @param uniques 参数
* @return cache key
*/
default CacheKey key(Object... uniques) {
String key = getKey(uniques);
ArgumentAssert.notEmpty(key, "key 不能为空");
return new CacheKey(key, getExpire());
}
/**
* 构建 redis 类型的 hash cache key
*
* @param field field
* @param uniques 动态参数
* @return cache key
*/
default CacheHashKey hashFieldKey(@NonNull Object field, Object... uniques) {
String key = getKey(uniques);
ArgumentAssert.notEmpty(key, "key 不能为空");
ArgumentAssert.notNull(field, "field 不能为空");
return new CacheHashKey(key, field, getExpire());
}
/**
* 构建 redis 类型的 hash cache key (无field)
*
* @param uniques 动态参数
* @return
*/
default CacheHashKey hashKey(Object... uniques) {
String key = getKey(uniques);
ArgumentAssert.notEmpty(key, "key 不能为空");
return new CacheHashKey(key, null, getExpire());
}
/**
* 根据动态参数 拼接key
* <p>
* key命名规范:[前缀:][租户ID:][服务模块名:]业务类型[:业务字段][:value类型][:业务值]
*
* @param uniques 动态参数
* @return
*/
default String getKey(Object... uniques) {
ArrayList<String> regionList = new ArrayList<>();
String prefix = this.getPrefix();
if (StrUtil.isNotEmpty(prefix)) {
regionList.add(prefix);
}
String tenant = this.getTenant();
// 租户编码:存储默认库的全局缓存,可以重写getTenant并返回null
if (StrUtil.isNotEmpty(tenant)) {
regionList.add(tenant);
}
// 服务模块名
String modular = getModular();
if (StrUtil.isNotEmpty(modular)) {
regionList.add(modular);
}
// 业务类型
String table = this.getTable();
ArgumentAssert.notEmpty(table, "缓存业务类型不能为空");
regionList.add(table);
// 业务字段
String field = getField();
if (StrUtil.isNotEmpty(field)) {
regionList.add(field);
}
// value类型
ValueType valueType = getValueType();
if (valueType != null) {
regionList.add(valueType.name());
}
// 业务值
for (Object unique : uniques) {
if (ObjectUtil.isNotEmpty(unique)) {
regionList.add(String.valueOf(unique));
}
}
return CollUtil.join(regionList, StrPool.COLON);
}
enum ValueType {
obj, string, number,
}
}
- 编写代码操作缓存
- 实现SuperCacheManager
- 自行调用CacheOps
- 自行调用CacheHashOps
- 自行调用RedisOps