缓存(forge-starter-cache)
Forge 的缓存模块基于 受管注解缓存(Managed Annotation Cache) 与 Redis / Redisson 实现。它不是 Spring Cache 的 @Cacheable,而是自研的一套注解:@ForgeCacheable / @ForgeCachePut / @ForgeCacheEvict / @ForgeCacheConfig,由 AOP 拦截、支持多级存储(本地 + Redis)、按租户 / 用户身份隔离缓存键,并可在管理后台按「缓存名 + 应用」动态治理策略。
引入依赖
<dependency>
<groupId>com.mdframe.forge</groupId>
<artifactId>forge-starter-cache</artifactId>
</dependency>缓存注解
@ForgeCacheable
方法级,命中即返回缓存,未命中则回源并写入。
@ForgeCacheable(cacheName = "sys_user", key = "#userId")
public SysUser getById(Long userId) {
return userMapper.selectById(userId);
}| 属性 | 必填 | 说明 |
|---|---|---|
cacheName | 是 | 缓存名 |
key | 否 | SpEL 表达式,如 #userId;留空则用全部方法入参 |
@ForgeCachePut
方法级,强制写入缓存(通常用于更新后回填)。
@ForgeCachePut(cacheName = "sys_user", key = "#user.userId")
public SysUser update(SysUser user) {
userMapper.updateById(user);
return user;
}@ForgeCacheEvict
方法级,失效缓存。
// 失效指定键
@ForgeCacheEvict(cacheName = "sys_user", key = "#userId")
public void delete(Long userId) { ... }
// 全量失效
@ForgeCacheEvict(cacheName = "sys_user", allEntries = true)
public void clearAll() { ... }| 属性 | 必填 | 说明 |
|---|---|---|
cacheName | 是 | 缓存名 |
key | 否 | SpEL 表达式 |
allEntries | 否 | 是否全量失效,默认 false |
@ForgeCacheConfig
类型级(@Inherited、可重复 @Repeatable),声明一个命名缓存的代码默认策略和不可变安全边界。
@ForgeCacheConfig(
name = "sys_user",
description = "用户缓存",
mode = CacheMode.REDIS,
allowedModes = { CacheMode.LOCAL, CacheMode.REDIS, CacheMode.MULTI },
scope = CacheScope.TENANT,
redisTtlSeconds = 1800,
localTtlSeconds = 60,
localMaxSize = 1000,
cacheNull = false,
nullTtlSeconds = 30
)
@Service
public class SysUserService { ... }| 属性 | 默认值 | 说明 |
|---|---|---|
name | —(必填) | 缓存名 |
description | "" | 缓存描述 |
mode | REDIS | 默认存储模式 |
allowedModes | LOCAL/REDIS/MULTI | 代码声明的不可变安全边界,运行时不能越界 |
scope | TENANT | 缓存键身份隔离范围 |
redisTtlSeconds | 1800 | Redis TTL(秒) |
localTtlSeconds | 60 | 本地 TTL(秒) |
localMaxSize | 1000 | 本地缓存容量 |
cacheNull | false | 是否缓存空值 |
nullTtlSeconds | 30 | 空值 TTL(秒) |
存储模式(CacheMode)
| 枚举 | 说明 |
|---|---|
LOCAL | 仅本地缓存(单机) |
REDIS | 仅 Redis |
MULTI | 多级:本地 + Redis |
身份隔离范围(CacheScope)
缓存键按可信身份隔离,避免跨租户 / 跨用户串数据:
| 枚举 | 隔离维度 |
|---|---|
GLOBAL | 全局共享 |
TENANT | 按租户隔离 |
TENANT_USER | 按租户 + 用户隔离 |
TENANT_USER_ORG | 按租户 + 用户 + 组织隔离 |
缓存键生成规则
key 只对代码内可信的 SpEL 求值,最终写入 Redis 的 entry key 始终是 SHA-256 摘要,并由 CacheScope 的隔离材料拼接(如 tenant:1:user:2):
scope材料 + "|" + SpEL结果(JSON) → SHA-256 摘要因此业务侧无需关心跨租户键冲突,也不建议直接手写 Redis key 与受管缓存混用。
编程式缓存(ICacheService)
除注解外,可注入 ICacheService 做命令式读写:
@Autowired
private ICacheService cacheService;
cacheService.set("user:1", user, 1, TimeUnit.HOURS); // 设置并指定过期
SysUser user = cacheService.get("user:1", SysUser.class); // 读取
cacheService.setIfAbsent("user:1", user, 1, TimeUnit.HOURS); // 仅不存在时写入
cacheService.delete("user:1"); // 删除命令式接口不经过
@ForgeCacheConfig的受管策略与身份隔离,适合工具类 / 临时缓存场景;业务主数据优先使用注解。
配置
配置前缀 forge.cache:
| 配置 | 默认值 | 说明 |
|---|---|---|
forge.cache.annotation-enabled | true | 是否启用注解拦截,关闭后业务方法全部穿透 |
forge.cache.application-code | spring.application.name | 应用编码 |
forge.cache.namespace | forge:managed-cache | Redis 控制面与数据对象前缀 |
forge.cache.policy-refresh-seconds | 30 | Pub/Sub 丢失时重新校准策略快照的最小间隔 |
Redis / Redisson 基础连接沿用标准配置:
spring:
data:
redis:
host: localhost
port: 6379
password:
database: 0运行时策略治理
受管缓存的运行策略(模式、TTL、容量、空值缓存)存放于 sys_cache_policy 表,可在管理后台 平台管理 → 运维监控 → 缓存监控 中按「应用编码 + 缓存名」在线编辑、重置、清空;allowedModes 仍是代码声明的不可变边界。详细说明见受管注解缓存。
注意事项
key只支持 SpEL,且只对方法入参 /#result求值,不要写外部表达式。allowedModes是代码不可变安全边界,运行策略不能越界改模式。- 更新数据时用
@ForgeCachePut回填或@ForgeCacheEvict失效,避免脏读。 - 合理设置 TTL 与
cacheNull,规避穿透、击穿、雪崩。
