cache-redis 组件是 EasyFK 框架的分布式 Redis 缓存方案,提供两种使用模式:
@Cacheable、@CachePut、@CacheEvict 等 Spring Cache 标准注解声明式管理缓存ICacheService 接口直接进行缓存的增删查改操作核心特性:
RedisCacheManager,引入即用db-redis 组件的多数据源连接管理,支持指定缓存使用的 Redis 数据源StringRedisSerializer 序列化,Value 序列化方式跟随 db-redis 全局配置null 值,避免缓存穿透cache-redis
├── easyfk-cache(缓存接口层,定义 ICacheService)
└── db-redis(Redis 连接管理,提供 RedisConnectionManager、RedisOptManager 等)dependencies {
implementation("com.mcst:cache-redis")
}<dependency>
<groupId>com.mcst</groupId>
<artifactId>cache-redis</artifactId>
</dependency>默认情况下,使用 Spring Boot 标准的 Redis 配置即可:
# Spring Redis 标准配置
spring:
data:
redis:
host: 127.0.0.1
port: 6379
password: your-password
database: 0
# cache-redis 缓存配置
easyfk:
config:
cache:
redis:
time-to-live: 30m # 全局默认 TTLdb-redis 组件的自定义配置指定缓存使用的数据源,详见多数据源场景。@Service
public class UserService {
@Cacheable(value = "users", key = "#userId")
public UserDTO getUserById(Long userId) {
return userMapper.selectById(userId);
}
}@Service
public class UserService {
@Resource
private ICacheService cacheService;
public UserDTO getUserById(Long userId) {
String key = "user:" + userId;
// 查询缓存
UserDTO user = cacheService.queryByKey(key, "user-ns");
if (user != null) {
return user;
}
// 缓存未命中,查询数据库
user = userMapper.selectById(userId);
if (user != null) {
cacheService.cacheObject(key, user, Duration.ofMinutes(30), "user-ns");
}
return user;
}
}配置前缀:easyfk.config.cache.redis
对应属性类:RedisCacheProperties
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
datasource | String | default | Redis 数据源名称(对应 db-redis 中配置的数据源) |
database-name | String | default | Redis 数据库名称(对应数据源下的库配置) |
time-to-live | Duration | 0 | 全局默认缓存过期时间(0 表示永不过期) |
caches | List | (空) | 自定义缓存空间配置列表 |
30m — 30 分钟2h — 2 小时1d — 1 天PT30S — 30 秒(ISO-8601 格式)0 — 永不过期不同的业务数据通常需要不同的过期时间。通过 caches 配置为每个缓存空间(cacheName)设置独立的 TTL:
easyfk:
config:
cache:
redis:
time-to-live: 30m
caches:
- cache-name: users
time-to-live: 2h
- cache-name: verify-code
time-to-live: 5m
- cache-name: dict
time-to-live: 1d| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
cache-name | String | 是 | — | 缓存空间名称,对应 @Cacheable(value = "xxx") |
time-to-live | Duration | 否 | 30m | 该缓存空间的过期时间 |
caches 列表时:RedisCacheManager 仅对列表中声明的缓存空间应用自定义 TTL 和序列化配置。未在列表中声明的缓存空间将使用 Spring Cache 的默认行为(无 TTL,允许缓存 null 值)。caches 时:全局配置(包含 time-to-live、序列化器、禁止缓存 null 值)将通过 cacheDefaults 应用到所有缓存空间,并启用事务感知(transactionAware)。如果需要让所有缓存空间都使用全局配置,不要配置 caches 列表,仅设置全局 time-to-live 即可。
默认情况下,使用 Spring Boot 标准 Redis 配置(spring.data.redis.*)即可,无需额外配置数据源。当需要多 Redis 数据源时,可通过 db-redis 组件管理多个数据源,并在 cache-redis 中通过 datasource + database-name 指定缓存使用哪个数据源和数据库:
easyfk:
config:
db:
redis:
redis-serializer: FastJSON # 序列化器,可选:DEFAULT / FastJSON / KRYO
default-data-source: default
datasource:
default:
host: 127.0.0.1
port: 6379
password: your-password
database: 0
databases:
default: 0
cache-db: 1 # 数据库别名 cache-db → 索引 1
cache:
redis:
datasource: default # 指定使用 db-redis 中的数据源名称
database-name: cache-db # 指定使用数据源中别名为 cache-db 的库(索引 1)
time-to-live: 30m
caches:
- cache-name: users
time-to-live: 2h
- cache-name: verify-code
time-to-live: 5mdatasource 和 database-name 的默认值均为 default,单数据源场景下无需配置database-name 对应数据源配置中 databases Map 的 key(别名),而不是 Redis 数据库索引数字组件自动配置的 RedisCacheManager 作为 Spring Cache 的缓存管理器,支持 @Cacheable、@CachePut、@CacheEvict 等标准注解。
StringRedisSerializer(字符串格式,便于在 Redis 客户端查看)db-redis 组件的 redis-serializer 全局配置null 值(disableCachingNullValues)@Primary 标记,当存在多个 CacheManager 时默认使用此实例@Lazy 延迟初始化,确保 Redis 连接工厂在初始化时已就绪ICacheService 是 EasyFK 缓存抽象接口,RedisCacheServiceImpl 为其 Redis 实现。
| 方法 | 参数 | 返回值 | 说明 |
|---|---|---|---|
cacheObject(key, value, namespace) | 键, 值, 命名空间 | BaseResult<?> | 写入缓存(永不过期) |
cacheObject(key, value, times, namespace) | 键, 值, 过期时间, 命名空间 | BaseResult<?> | 写入缓存(指定过期时间) |
queryByKey(key, namespace) | 键, 命名空间 | T | 查询缓存值 |
existKey(key, namespace) | 键, 命名空间 | boolean | 判断 Key 是否存在 |
removeKey(key, namespace) | 键, 命名空间 | BaseResult<?> | 删除缓存 |
expireKey(key, times, namespace) | 键, 过期时间, 命名空间 | void | 设置过期时间 |
expireKeyAt(key, date, namespace) | 键, 到期日期, 命名空间 | void | 设置到期时间点 |
getKeyExpire(key, namespace) | 键, 命名空间 | long | 获取剩余过期时间 |
getSetCountByKey(pattern, namespace) | 模式, 命名空间 | Long | 获取 Set 集合大小 |
key:缓存键,由业务自行定义namespace:命名空间,用于 Key 前缀隔离不同业务的数据times:java.time.Duration 类型的过期时间datasource + databaseName 指定的 Redis 实例@Service
public class ProductService {
@Cacheable(value = "products", key = "#productId")
public ProductDTO getProduct(Long productId) {
return productMapper.selectById(productId);
}
@CachePut(value = "products", key = "#product.id")
public ProductDTO updateProduct(ProductDTO product) {
productMapper.updateById(product);
return product;
}
@CacheEvict(value = "products", key = "#productId")
public void deleteProduct(Long productId) {
productMapper.deleteById(productId);
}
@CacheEvict(value = "products", allEntries = true)
public void refreshAllProducts() {
// 触发全量刷新
}
}@Cacheable(value = "user-roles", key = "#userId + ':' + #appId")
public List<RoleDTO> getUserRoles(Long userId, String appId) {
return roleMapper.selectByUserAndApp(userId, appId);
}@Cacheable(value = "users", key = "#userId", unless = "#result == null")
public UserDTO getUser(Long userId) {
return userMapper.selectById(userId);
}
@Cacheable(value = "users", key = "#userId", condition = "#userId > 0")
public UserDTO getUser(Long userId) {
return userMapper.selectById(userId);
}@Service
public class OrderService {
@Resource
private ICacheService cacheService;
private static final String NS = "order";
public OrderDTO getOrder(String orderId) {
OrderDTO order = cacheService.queryByKey(orderId, NS);
if (order != null) {
return order;
}
order = orderMapper.selectById(orderId);
if (order != null) {
cacheService.cacheObject(orderId, order, NS);
}
return order;
}
}public void cacheVerifyCode(String phone, String code) {
cacheService.cacheObject("verify:" + phone, code, Duration.ofMinutes(5), "auth");
}
public void cacheToken(String token, UserSession session) {
cacheService.cacheObject(token, session, Duration.ofHours(2), "session");
}boolean exists = cacheService.existKey("user:10001", "user");
cacheService.removeKey("user:10001", "user");cacheService.expireKey("token:abc123", Duration.ofHours(2), "session");
Date activityEndTime = parseDate("2026-12-31 23:59:59");
cacheService.expireKeyAt("activity:config", activityEndTime, "activity");
long ttl = cacheService.getKeyExpire("token:abc123", "session");
log.info("Token 剩余有效期: {} 秒", ttl);默认情况下使用 Spring Boot 标准 Redis 配置(spring.data.redis.*)。如果需要多数据源,通过 db-redis 组件的自定义配置(easyfk.config.db.redis)管理,详见多数据源场景。
组件默认配置了 disableCachingNullValues(),这意味着:
@Cacheable 方法返回 null 时不会写入缓存null@Cacheable(value = "users") 中的 value 对应 YAML 配置中 caches 列表里的 cache-name:
caches:
- cache-name: users
time-to-live: 2hcaches 中声明的缓存名称,该缓存空间将使用 Spring Cache 的默认行为(无 TTL,允许缓存 null 值),而非全局 time-to-live。cacheName::key(Spring Cache 默认的 :: 分隔)namespace::key(由 RedisUtil.wrapKey() 拼接)Value 序列化器由 db-redis 的 easyfk.config.db.redisson.redis-serializer 全局控制,可选值为 RedisValueSerializer 枚举:
| 值 | 说明 |
|---|---|
DEFAULT | 默认序列化器(SmartRedisSerializer) |
FastJSON | FastJSON 序列化 |
KRYO | Kryo 序列化 |
确保缓存对象可被配置的序列化器正确序列化/反序列化。
建议使用小写字母 + 短横线的命名规范:
✅ 推荐: users, order-details, verify-code, sys-config
❌ 避免: Users, orderDetails, VERIFY_CODE, sys.configTTL 过短 → 缓存命中率低 → Redis 压力小,数据源压力大
TTL 过长 → 缓存命中率高 → 数据一致性差,内存占用大| 数据类型 | 推荐 TTL | 说明 |
|---|---|---|
| 验证码 | 5m | 短时效 |
| 登录 Token / Session | 2h ~ 24h | 根据安全策略 |
| 用户信息 | 30m ~ 2h | 变更后主动失效 |
| 商品详情 | 15m ~ 1h | 取决于更新频率 |
| 字典/配置数据 | 6h ~ 24h | 几乎不变 |
| 统计数据 | 5m ~ 30m | 允许短暂延迟 |
对于需要批量查询的场景,避免循环调用单个 Key 查询,考虑使用 db-redis 组件的 Pipeline 或 Multi 操作。
对于冷启动后短时间大量请求的场景,建议在应用启动时主动预加载热点数据到缓存:
@Component
public class CacheWarmer implements CommandLineRunner {
@Resource
private ICacheService cacheService;
@Resource
private DictMapper dictMapper;
@Override
public void run(String... args) {
List<DictDTO> dictList = dictMapper.selectAll();
dictList.forEach(dict ->
cacheService.cacheObject(
dict.getType() + ":" + dict.getCode(),
dict,
Duration.ofHours(24),
"dict"
)
);
log.info("字典缓存预热完成,共 {} 条", dictList.size());
}
}生产环境建议缓存使用独立的 Redis 实例(与业务数据分离),通过 datasource 配置指向专用实例:
allkeys-lru 淘汰策略noeviction 策略保证数据不丢失原因:未配置 db-redis 组件的 Redis 数据源。cache-redis 依赖 db-redis 提供连接管理。
解决:在 application.yml 中添加 easyfk.config.db.redis.datasource 配置。
常见原因:
@Cacheable 不生效(Spring AOP 代理限制)public 的// 错误:自调用不走代理
@Service
public class UserService {
public void process() {
getUserById(1L); // ← 不会走缓存!
}
@Cacheable(value = "users", key = "#userId")
public UserDTO getUserById(Long userId) { ... }
}
// 正确:通过注入自身或拆分到不同 Service
@Service
public class UserService {
@Resource
private UserCacheService userCacheService;
public void process() {
userCacheService.getUserById(1L); // ← 正常走缓存
}
}@CachePut 或 @CacheEvictvalue 和 key 与查询时一致removeKey 或重新 cacheObject使用 Redis 客户端工具(如 Redis Insight、redis-cli)连接对应实例:
redis-cli> keys users::*
redis-cli> get users::10001
redis-cli> keys *order*time-to-live: 0 表示缓存永不过期(需手动失效或等 Redis 内存淘汰),不建议在生产环境使用。建议至少配置一个合理的全局默认值。
不建议同时引入。两者都会注册 CacheManager Bean,可能导致冲突。选择其一:
cache-rediscache-mult直接在注解的 value 参数中指定不同的缓存空间名称:
@Cacheable(value = "users", key = "#userId")
public UserDTO getUser(Long userId) { ... }
@Cacheable(value = "products", key = "#productId")
public ProductDTO getProduct(Long productId) { ... }每个缓存空间的 TTL 在 YAML 的 caches 列表中独立配置。
cache-redis — 分布式缓存,加速数据访问。