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

自定义RedisTemplate序列化器

大纲

  • RedisSerializer
  • FastJsonRedisSerializer
  • 自定义二进制序列化器
  • 总结
  • 代码

在《RedisTemplate保存二进制数据的方法》一文中,我们将Java对象通过《使用java.io库序列化Java对象》中介绍的方法转换为二进制数组,然后保存到Redis中。实际可以通过定制RedisTemplate序列化器来避开手工序列化和反序列化的工作。本文我们将介绍3种常见的序列化器。

RedisSerializer

package org.example.redistemplateexample.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;@Configuration
public class RedisTemplateBeansConfig {@Bean(name = "nomaljsonRedisTemplate")public <T> RedisTemplate<String, T> nomaljsonRedisTemplate(RedisConnectionFactory connectionFactory) {RedisTemplate<String, T> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(connectionFactory);redisTemplate.setValueSerializer(RedisSerializer.json());redisTemplate.setHashValueSerializer(RedisSerializer.json());redisTemplate.setKeySerializer(RedisSerializer.string());redisTemplate.setHashKeySerializer(RedisSerializer.string());redisTemplate.afterPropertiesSet();return redisTemplate;}
}

主要设置ValueSerializer和HashValueSerializer。RedisSerializer.json()会将模板类型T的对象序列化为Json,然后保存到Redis中。
然后定义一个操作类,并使用上面创建的名字为nomaljsonRedisTemplate的redisTemplate。

package org.example.redistemplateexample.redis;import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;import jakarta.annotation.Resource;@Component
public class NomalJsonOperation<T> {@Resource(name = "nomaljsonRedisTemplate")public RedisTemplate<String, T> redisTemplate;public void Set(String key, T value) {redisTemplate.opsForValue().set(key, value);}public T Get(String key) {return redisTemplate.opsForValue().get(key);}
}

测试代码如下

package org.example.redistemplateexample.redis;import org.example.redistemplateexample.pojo.BaseTypes;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
public class NomalJsonOperationTest {@Autowiredprivate NomalJsonOperation<BaseTypes> nomalJsonOperation;@Testpublic void testSetGet() {String key = "NomalJsonOperationTest";BaseTypes value = generate(2);nomalJsonOperation.Set(key, value);BaseTypes result = nomalJsonOperation.Get(key);assertEquals(value, result);}private BaseTypes generate(int mark) {BaseTypes baseTypes = new BaseTypes();baseTypes.setByteValue((byte) mark);baseTypes.setShortValue((short) mark);baseTypes.setIntValue(mark);baseTypes.setLongValue((long) mark);baseTypes.setFloatValue((float) mark);baseTypes.setDoubleValue((double) mark);baseTypes.setCharValue((char) mark);baseTypes.setBooleanValue(mark % 2 == 0);return baseTypes;}
}

在这里插入图片描述

FastJsonRedisSerializer

fastjson是阿里巴巴公司推出的json序列化库,在现实生产中广泛应用。
但是在我们的场景下,使用fastjson需要做一些特殊处理,模式也和其他两者不一样。

package org.example.redistemplateexample.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer;@Configuration
public class RedisTemplateBeansConfig {@Bean(name = "fastjsonRedisTemplate")public RedisTemplate<String, Object> fastjsonRedisTemplate(RedisConnectionFactory connectionFactory) {RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(connectionFactory);redisTemplate.setValueSerializer(new FastJsonRedisSerializer(Object.class));redisTemplate.setHashValueSerializer(new FastJsonRedisSerializer(Object.class));redisTemplate.setKeySerializer(RedisSerializer.string());redisTemplate.setHashKeySerializer(RedisSerializer.string());redisTemplate.afterPropertiesSet();return redisTemplate;}
}

可以看到,我们需要使用RedisTemplate<String, Object>,即模板类的第二类名需要使用Object。这是因为FastJsonRedisSerializer的构造需要指定Class<T>,而我们又不能通过函数的返回值类型T推导出Class<T>,所以只能使用Object.class这种通用的类型。当然,如果不需要使用模板类型,即让RedisTemplate只支持某个特定类型的Value,则可以直接指定确定的类型,而不用使用Object。
相对应的操作类,Get方法也只能返回Object,而不是模板类型T。

package org.example.redistemplateexample.redis;import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;import jakarta.annotation.Resource;@Component
public class FastJsonOperation<T>  {@Resource(name = "fastjsonRedisTemplate")public RedisTemplate<String, T> redisTemplate;public void Set(String key, T value) {redisTemplate.opsForValue().set(key, value);}public Object Get(String key) {return redisTemplate.opsForValue().get(key);}
}

测试的代码如下

package org.example.redistemplateexample.redis;import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import org.example.redistemplateexample.pojo.BaseTypes;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
public class FastJsonOperationTest {@Autowiredprivate FastJsonOperation<BaseTypes> fastJsonOperation;@Testpublic void testSetGet() {String key = "FastJsonOperationTest";BaseTypes value = generate(2);fastJsonOperation.Set(key, value);BaseTypes result = JSONObject.parseObject(JSON.toJSONString(fastJsonOperation.Get(key)), BaseTypes.class);assertEquals(value, result);}private BaseTypes generate(int mark) {BaseTypes baseTypes = new BaseTypes();baseTypes.setByteValue((byte) mark);baseTypes.setShortValue((short) mark);baseTypes.setIntValue(mark);baseTypes.setLongValue((long) mark);baseTypes.setFloatValue((float) mark);baseTypes.setDoubleValue((double) mark);baseTypes.setCharValue((char) mark);baseTypes.setBooleanValue(mark % 2 == 0);return baseTypes;}
}

我们需要使用JSON.toJSONString将Fastjson序列化后的object转换成Json字符串,然后再使用JSONObject.parseObject将其转化成明确的类型BaseTypes。
这种转换让Fastjson方案黯然失色。
在这里插入图片描述

自定义二进制序列化器

最后我们介绍结合了《使用java.io库序列化Java对象》和《RedisTemplate保存二进制数据的方法》的方式。
首先定义序列化器IoSerializer,它继承于RedisSerializer。中间的序列化和反序列化步骤已经在《使用java.io库序列化Java对象》中有过介绍。

package org.example.redistemplateexample.config;import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;public class IoSerializer<T> implements RedisSerializer<T> {@Overridepublic byte[] serialize(T obj) throws SerializationException {if (obj == null) {return new byte[0];}ByteArrayOutputStream bos = new ByteArrayOutputStream();try (ObjectOutputStream oos = new ObjectOutputStream(bos)) {oos.writeObject(obj);return bos.toByteArray();} catch (Exception e) {throw new SerializationException("Failed to serialize", e);}}@Overridepublic T deserialize(byte[] bytes) throws SerializationException {if (bytes == null || bytes.length == 0) {return null;}ByteArrayInputStream bis = new ByteArrayInputStream(bytes);try( ObjectInputStream ois = new ObjectInputStream(bis)) {T obj = (T) ois.readObject();return obj;} catch (Exception e) {throw new SerializationException("Failed to deserialize", e);}}
}

然后设置序列化器

package org.example.redistemplateexample.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;@Configuration
public class RedisTemplateBeansConfig {@Bean(name = "iomemoryRedisTemplate")public <T> RedisTemplate<String, T> iomemoryRedisTemplate(RedisConnectionFactory connectionFactory) {RedisTemplate<String, T> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(connectionFactory);redisTemplate.setValueSerializer(new IoSerializer<T>());redisTemplate.setHashValueSerializer(new IoSerializer<T>());redisTemplate.setKeySerializer(RedisSerializer.string());redisTemplate.setHashKeySerializer(RedisSerializer.string());redisTemplate.afterPropertiesSet();return redisTemplate;}
}

再定义个操作类

package org.example.redistemplateexample.redis;import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;import jakarta.annotation.Resource;@Component
public class IoMemoryOperation<T> {@Resource(name = "iomemoryRedisTemplate")public RedisTemplate<String, T> redisTemplate;public void Set(String key, T value) {redisTemplate.opsForValue().set(key, value);}public T Get(String key) {return redisTemplate.opsForValue().get(key);}
}

测试代码如下

package org.example.redistemplateexample.redis;import org.example.redistemplateexample.pojo.BaseTypes;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
public class IoMemoryOperationTest {@Autowiredprivate IoMemoryOperation<BaseTypes> ioMemoryOperation;@Testpublic void testSetGet() {String key = "IoMemoryOperationTest";BaseTypes value = generate(2);ioMemoryOperation.Set(key, value);BaseTypes result = ioMemoryOperation.Get(key);assertEquals(value, result);}private BaseTypes generate(int mark) {BaseTypes baseTypes = new BaseTypes();baseTypes.setByteValue((byte) mark);baseTypes.setShortValue((short) mark);baseTypes.setIntValue(mark);baseTypes.setLongValue((long) mark);baseTypes.setFloatValue((float) mark);baseTypes.setDoubleValue((double) mark);baseTypes.setCharValue((char) mark);baseTypes.setBooleanValue(mark % 2 == 0);return baseTypes;}
}

在这里插入图片描述

总结

  • 广泛使用的Fastjson在使用模板类时,类型转换比较丑陋。
  • iomemoryRedisTemplate和nomaljsonRedisTemplate被限制在Java工程中。特别是iomemoryRedisTemplate方案,因为它保存的是Java对象的二进制值。

代码

https://github.com/f304646673/RedisTemplateExample

http://www.lryc.cn/news/354225.html

相关文章:

  • Flutter 中的 CupertinoContextMenuAction 小部件:全面指南
  • Element-Ul快速入门
  • Django的模型层——2模型实例
  • Python筑基之旅-MySQL数据库(四)
  • OceanBase SQL 诊断和调优实践——【DBA从入门到实践】第七期
  • C++之std::is_trivially_copyable(平凡可复制类型检测)
  • 宝石收集,tarjan
  • python 面对对象 类 继承
  • Rust腐蚀怎么用服务器一键开服联机教程
  • 公共代理IP和独享代理IP之间的区别?
  • 基于Vue的前端自定义询问弹框与输入弹框组件的设计与实践
  • 淘宝订单系统ERP中如何接入平台订单信息?(订单API)
  • 在Spring Boot项目中集成和使用MQTT
  • 14、设计模式之访问者模式
  • Excel如何换行不换格
  • Elasticsearch 8.1官网文档梳理 - 十五、Aggregations(聚合)
  • 计算机系统概论
  • 【Vue】diff 算法
  • Spring Boot 3.x 与 Spring Boot 2.x 的对比
  • SSLError ClosedPoolError
  • 勒索软件分析_Conti
  • Linux系统如何通过编译方式安装python3.11.3
  • 仿《Q极速体育》NBACBA体育直播吧足球直播综合体育直播源码
  • 代码随想录算法训练营第四天| 24. 两两交换链表中的节点、19.删除链表的倒数第N个节点 、 面试题 02.07. 链表相交、142.环形链表II
  • 吉林大学计科21级《软件工程》期末考试真题
  • AWS云服务器每月费用高昂,如何优化达到节省目的?
  • 关于XtremIO 全闪存储维护的一些坑(建议)
  • 《最新出炉》系列入门篇-Python+Playwright自动化测试-41-录制视频
  • 一个程序员的牢狱生涯(38)答案
  • MySQL命令