自定义RedisTemplate序列化器

news2024/11/15 16:51:03

大纲

  • 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 {

    @Autowired
    private NomalJsonOperation<BaseTypes> nomalJsonOperation;
    
    @Test
    public 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 {

    @Autowired
    private FastJsonOperation<BaseTypes> fastJsonOperation;
    
    @Test
    public 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> {

    @Override
    public 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);
        }
    }

    @Override
    public 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 {
    @Autowired
    private IoMemoryOperation<BaseTypes> ioMemoryOperation;

    @Test
    public 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.coloradmin.cn/o/1684615.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

QTextCodec NO such file or directory让qt6兼容qt5

首先在.pro 文件中新加 QT core5compat这时会报错 链接 报错之后修复qt&#xff0c;新加兼容模块&#xff0c;见链接。

C++实现基于http协议的epoll非阻塞模型的web服务器框架(支持访问服务器目录下文件的解析)

使用方法&#xff1a; 编译 例子&#xff1a;./httpserver 9999 ../ htmltest/ 可执行文件 端口 要访问的目录下的 例子&#xff1a;http://192.168.88.130:9999/luffy.html 前提概要 http协议 &#xff1a;应用层协议&#xff0c;用于网络通信&#xff0c;封装要传输的数据&…

LeetCode 79.单词搜索

原题链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 单词必须按照字母顺序&#xff0c;通过相邻的单元格内…

本地centos7+docker+ollama+gpu部署

1、一台有 NVIDIA GPU 驱动的机器 2、Docker CE安装 # 删除旧版本的 Docker&#xff08;如果存在&#xff09; sudo yum remove -y docker docker-common docker-selinux docker-engine # 安装必要的软件包&#xff1a; sudo yum install -y yum-utils device-mapper-persiste…

PyCharm设置——用于调试虚拟环境中的django程序

使用Pycharm新建了一个项目。 项目目录&#xff1a;C:\Users\grace\PycharmProjects\learning_log 在该路径下安装虚拟环境ll_env&#xff0c;并在虚拟环境下安装Django。 为了调试该Django需要对PyCharm进行设置。 1、确保PyCharm使用正确的虚拟环境 打开PyCharm&#xff…

市面上前 11 名的 Android 数据恢复软件

Android数据恢复软件是恢复无意中删除的文件或文件夹的必要工具。该软件还将帮助您恢复丢失或损坏的信息。本文介绍提供数据备份和磁盘克隆选项的程序&#xff0c;这些选项有助于在Android设备上恢复文件的过程。 如果您正在寻找一种有效的方法来恢复图像&#xff0c;文档&…

qmt量化交易策略小白学习笔记第8期【qmt编程之获取股票资金流向数据--内置Python】

qmt编程之获取股票资金流向数据 qmt更加详细的教程方法&#xff0c;会持续慢慢梳理。 也可找寻博主的历史文章&#xff0c;搜索关键词查看解决方案 &#xff01; 感谢关注&#xff0c;需免费开通量化回测与咨询实盘权限&#xff0c;可以和博主联系&#xff01; 获取股票资金…

java学习四

Random 随机数 数组 静态初始化数组 数组在计算机中的基本原理 数组的访问 什么是遍历 数组的动态初始化 动态初始化数组元素默认值规则 Java内存分配介绍 数组在计算机中的执行原理 使用数组时常见的一个问题 案例求数组元素最大值 public class Test1 {public static void ma…

面试八股之MySQL篇5——主从同步原理篇

&#x1f308;hello&#xff0c;你好鸭&#xff0c;我是Ethan&#xff0c;一名不断学习的码农&#xff0c;很高兴你能来阅读。 ✔️目前博客主要更新Java系列、项目案例、计算机必学四件套等。 &#x1f3c3;人生之义&#xff0c;在于追求&#xff0c;不在成败&#xff0c;勤通…

Qt学习记录(14)线程

前言&#xff1a; 我的臀部已经翘到可以顶起一屁股债了 为什么要使用线程 什么时候用线程 复杂的数据处理 头文件.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTimer>//定时器头文件QT_BEGIN_NAMESPACE namespace Ui { class Widget; }…

表现层框架设计之表现层设计模式_3.MVVM模式

1.MVVM模式 MVVM模式正是为解决MVP中UI种类变多&#xff0c;接口也会不断增加的问题而提出的。 MVVM模式全称是模型-视图-视图模型&#xff08;Model-View-ViewModel&#xff09;&#xff0c;它和MVC、MVP类似&#xff0c;主要目的都是为了实现视图和模型的分离&#xff0c;不…

Mac网线连接windows本【局域网互传文件】

Mac网线连接windows本【局域网互传文件】 两台电脑网线互联 Mac->网络->USP TCP/IP 手动配置IP&#xff0c;子网掩码&#xff0c;路由器 windows 网络和Internet配置->更改适配器选项->以太网->Internet协议版本4&#xff08;TCP/IPv4&#xff09;->属性 …

概率论统计——大数定律

大数定律 弱大数定律&#xff08;辛钦大数定律&#xff09; 利用切比雪夫不等式&#xff0c;证明弱大数定律 应用 伯努利大数定理&#xff0c;&#xff08;辛钦大数定理的推论&#xff09; 证明伯努利大数定理 注意&#xff1a;这里将二项分布转化成0,1分布来表示&#xff0c;…

跨境小白shopee被封号的原因?如何有效预防?

提到跨境电商平台&#xff0c;大家都知道亚马逊、Temu、TikTok shop这些是比较大的电商平台。但最近几年&#xff0c;在东南亚市场上&#xff0c;Shopee虾皮却是颇负盛名的一个跨境电商平台&#xff0c;这也让众多中国跨境小白蜂拥而至。目前shopee的商家正在不断增多&#xff…

奥威BI软件能做金蝶ERP以外的数据分析吗?

奥威BI软件能够进行金蝶ERP以外的数据分析。除了金蝶ERP外&#xff0c;奥威BI软件还可以对接用友等主流ERP&#xff1b;支持MS SQL、Oracle、Mysql等主流的关系型数据库&#xff0c;这允许用户直接从这些数据库中导入和分析数据&#xff1b;可以直接上传Excel文件作为数据源。 …

Prompt Engineering Guide

本文转载自&#xff1a;Prompt Engineering Guide https://www.promptingguide.ai/zh/introduction/basics 文章目录 提示工程简介1、基本概念1&#xff09;基础提示词2&#xff09;提示词格式 2、提示词要素3、设计提示的通用技巧从简单开始指令具体性避免不精确做还是不做&am…

编译aosp刷入pixel 真机得问题记录

编译aosp要做什么&#xff08;ubuntu下编译问题相对少&#xff09; 需要vmware并且已经安装了ubuntu镜像系统 直接切换到root 避免后期避免麻烦 参考地址 https://mp.weixin.qq.com/s/yJp3ijIxykiMmNVYr2V1nQ apt install git //安装git sudo apt install git//给git设置用户…

CDN用户平台安装说明

CDN用户平台安装说明 登录管理员系统 在”系统设置” – “高级设置” – “用户节点”中点击”添加节点” 如果所示&#xff1a; 节点名称 - 可以任意填写 进程监听端口 - 启动用户节点后&#xff0c;进程所监听的端口&#xff0c;通常是HTTP 80或者HTTPS 443&#xff0c;…

Django中使用Celery(通用方案、官方方案)

Django中使用Celery&#xff08;通用方案、官方方案&#xff09; 目录 Django中使用Celery&#xff08;通用方案、官方方案&#xff09;通用方案场景前置准备完整代码 Celery官方方案【1】注册celery配置【2】创建celery文件【3】init注册【4】添加任务【5】启动worker异步任务…

网络协议——Modbus-TCP

目录 1、简介 2、Modbus-TCP与Modbus-RTU的区别 3、消息格式 4、功能码01H 5、功能码02H 6、功能码03H 7、功能码04H 8、功能码05H 9、功能码06H 10、功能码0FH 11、功能码10H 1、简介 Modbus-TCP&#xff08;Modbus Transmission Control Protocol&#xff09;是一…