当前位置: 首页 > news >正文

Spring Cache 多级缓存中 ZSet 类型 Redis 缓存的自定义实现与核心功能

需求背景:spring cache 使用多级缓存,缓存实现方式用redis时,默认存储的结构是string,结果,但项目中需要使用其他结果,于是想到自己定义一个实现类,然后根据类型进行切换不同的实现方式,于是乎有了下面的zset自定义实现代码

import com.alibaba.fastjson.JSON;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisConnectionUtils;
import org.springframework.data.redis.connection.Tuple;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;/*** 精简版 ZSet 缓存(仅保留核心方法)* 功能:存储 List 元素、读取所有元素、清空缓存、获取元素数量*/
public class ZSetRedisCache extends RedisCache {// 匹配后缀的正则(仅在允许重复时使用)private static final Pattern SUFFIX_PATTERN = Pattern.compile("_.+?_\\d+$");// 元素序列化器(纯 JSON)private static final RedisSerializer<Object> ELEMENT_SERIALIZER = new FastJsonRedisSerializer<>();private final Duration ttl;private final RedisConnectionFactory connectionFactory;private final boolean allowDuplicate;// 仅保留必要的构造器参数public ZSetRedisCache(String name,RedisCacheWriter cacheWriter,RedisCacheConfiguration config,RedisConnectionFactory connectionFactory,boolean allowDuplicate) {super(name, cacheWriter, config);this.ttl = config.getTtl();this.connectionFactory = connectionFactory;this.allowDuplicate = allowDuplicate;}/*** 核心:存储 List 元素(批量添加到 ZSet)* 入参:value 必须是 List 类型,key 可忽略*/@Overridepublic void put(Object key, Object value) {if (value == null || !(value instanceof List<?>)) {return;}List<?> dataList = (List<?>) value;if (dataList.isEmpty()) {return;}RedisConnection connection = getRedisConnection();try {byte[] zsetKey = getNameBytes();if (zsetKey == null) {return;}// 序列化元素为 byte[]List<byte[]> memberBytesList = dataList.stream().map(ELEMENT_SERIALIZER::serialize).filter(Objects::nonNull).collect(Collectors.toList());if (memberBytesList.isEmpty()) {return;}// 处理重复元素(添加唯一后缀)if (allowDuplicate) {memberBytesList = addUniqueSuffix(memberBytesList);}// 构建 Tuple 集合(适配底层方法)Set<Tuple> tuples = memberBytesList.stream().map(bytes -> new DefaultTuple(bytes, 0.0)).collect(Collectors.toSet());// 批量添加到 ZSetconnection.zAdd(zsetKey, tuples);// 设置过期时间if (!ttl.isNegative()) {connection.expire(zsetKey, ttl.getSeconds());}} finally {releaseRedisConnection(connection);}}/*** 核心:读取所有元素(自动处理重复元素的后缀)*/public List<Object> getAllElements() {RedisConnection connection = getRedisConnection();try {byte[] zsetKey = getNameBytes();if (zsetKey == null) {return Collections.emptyList();}// 获取所有元素Set<Tuple> tuples = connection.zRangeWithScores(zsetKey, 0, -1);if (tuples.isEmpty()) {return Collections.emptyList();}// 反序列化并处理后缀return tuples.stream().map(Tuple::getValue).filter(Objects::nonNull).map(bytes -> {String elementStr = new String(bytes, StandardCharsets.UTF_8);// 去除重复元素的后缀if (allowDuplicate) {elementStr = SUFFIX_PATTERN.matcher(elementStr).replaceAll("");}return ELEMENT_SERIALIZER.deserialize(elementStr.getBytes(StandardCharsets.UTF_8));}).filter(Objects::nonNull).collect(Collectors.toList());} finally {releaseRedisConnection(connection);}}/*** 核心:获取元素总数量*/public Long getTotalCount() {RedisConnection connection = getRedisConnection();try {byte[] zsetKey = getNameBytes();return zsetKey != null ? connection.zCard(zsetKey) : 0L;} finally {releaseRedisConnection(connection);}}/*** 核心:清空缓存*/@Overridepublic void clear() {RedisConnection connection = getRedisConnection();try {byte[] zsetKey = getNameBytes();if (zsetKey != null) {connection.del(zsetKey);}} finally {releaseRedisConnection(connection);}}// -------------------------- 仅保留必要的工具方法 --------------------------/*** 为重复元素添加唯一后缀(内部使用)*/private List<byte[]> addUniqueSuffix(List<byte[]> memberBytesList) {List<byte[]> uniqueMembers = new ArrayList<>();String suffix = "_" + System.currentTimeMillis() + "_";for (int i = 0; i < memberBytesList.size(); i++) {byte[] origin = memberBytesList.get(i);byte[] suffixBytes = (suffix + i).getBytes(StandardCharsets.UTF_8);byte[] unique = Arrays.copyOf(origin, origin.length + suffixBytes.length);System.arraycopy(suffixBytes, 0, unique, origin.length, suffixBytes.length);uniqueMembers.add(unique);}return uniqueMembers;}/*** 缓存名序列化(内部使用)*/private byte[] getNameBytes() {return getName().getBytes(StandardCharsets.UTF_8);}/*** Redis 连接管理(内部使用)*/private RedisConnection getRedisConnection() {return RedisConnectionUtils.getConnection(connectionFactory);}private void releaseRedisConnection(RedisConnection connection) {RedisConnectionUtils.releaseConnection(connection, connectionFactory);}// -------------------------- 必要的内部类 --------------------------/*** 序列化器(内部使用)*/private static class FastJsonRedisSerializer<T> implements RedisSerializer<T> {@Overridepublic byte[] serialize(T t) throws SerializationException {if (t == null) {return new byte[0];}return JSON.toJSONString(t).getBytes(StandardCharsets.UTF_8);}@Overridepublic T deserialize(byte[] bytes) throws SerializationException {if (bytes == null || bytes.length == 0) {return null;}return (T) JSON.parse(bytes);}}/*** Tuple 实现(适配底层方法,内部使用)*/private static class DefaultTuple implements Tuple {private final byte[] value;private final double score;public DefaultTuple(byte[] value, double score) {this.value = value;this.score = score;}@Overridepublic byte[] getValue() {return value;}@Overridepublic Double getScore() {return score;}}
}

http://www.dtcms.com/a/544223.html

相关文章:

  • 从开源到落地:SimpleBGC 三轴稳像平台全栈技术解析(上)
  • 51、STM32 与 ESP32 单片机全面对比:架构、性能与应用场景详解
  • NodeJs
  • 【面试题】缓存先删漏洞解决策略(示例代码)
  • 操作系统(7)虚拟内存-缓存工具-页命中和缺页(3)
  • 旧衣回收小程序的技术架构与商业落地:开发者视角的全链路解析
  • 丽水建设网站织梦网站发布的哪些产品和文章放在a文件可以吗
  • 南京网站设计公司济南兴田德润优惠吗泉州定制网站建设
  • 【设计模式笔记10】:简单工厂模式示例
  • wordpress多站批量发布wordpress 图像描述
  • 永宝网站建设招聘信息松江做移动网站
  • 云手机 基于云计算的虚拟手机
  • 广州网站制作哪家专业网站开发分为哪几种类型
  • server 2012 做网站常州市新北区建设与管理局网站
  • 百度的网站网址做网站所用的工具
  • 网站统计功能设计旭泽建站
  • 网站建设心得8000字权威发布图片红字
  • 阿里做网站重庆市住房和城乡建设人才促进网
  • 个人业务网站教程合肥响应式网站建设方案
  • 广州建站业务公司亚马逊 wordpress
  • 北京知名网站建设wordpress二开
  • 做公众号要不要有自己的网站网站开发seo要求
  • 旅游网站ppt应做的内容上海猎头公司名单
  • 网站建设提案天空人体网站怎么做
  • 建设网站一般要多钱建设小说网站小说源
  • 东莞长安网站湖北网站建设的释义
  • 合肥地区建网站公司网站做多个页面
  • 如何查企业做网站是否备案过网站免费建立
  • 大连网站设计报价微信开店哪个平台好
  • 3 建设营销型网站流程西安百度关键词优化排名