Redisson自定义序列化

news2024/11/27 17:42:28

配置RedissonClient

@Bean
public RedissonClient redissonClient() {
    Config config = new Config();
    // 单节点模式
    SingleServerConfig singleServerConfig = config.useSingleServer();
    singleServerConfig.setAddress("redis://127.0.0.1:6379");
    singleServerConfig.setPassword("");
    // 使用json序列化方式
    Codec codec = new JsonJacksonCodec();
    config.setCodec(codec);
    RedissonClient redissonClient = Redisson.create(config);
    return redissonClient;
}

除上方配置的单机模式,其它模式配置:

数据序列化

Redisson的对象编码类是用于将对象进行序列化和反序列化,以实现对该对象在Redis里的读取和存储。Redisson提供了以下几种的对象编码应用,以供大家选择:

编码类名称

说明

org.redisson.codec.JsonJacksonCodec

Jackson JSON 编码 默认编码

org.redisson.codec.AvroJacksonCodec

Avro 一个二进制的JSON编码

org.redisson.codec.SmileJacksonCodec

Smile 另一个二进制的JSON编码

org.redisson.codec.CborJacksonCodec

CBOR 又一个二进制的JSON编码

org.redisson.codec.MsgPackJacksonCodec

MsgPack 再来一个二进制的JSON编码

org.redisson.codec.IonJacksonCodec

Amazon Ion 亚马逊的Ion编码,格式与JSON类似

org.redisson.codec.KryoCodec

Kryo 二进制对象序列化编码

org.redisson.codec.SerializationCodec

JDK序列化编码

org.redisson.codec.FstCodec

FST 10倍于JDK序列化性能而且100%兼容的编码

org.redisson.codec.LZ4Codec

LZ4 压缩型序列化对象编码

org.redisson.codec.SnappyCodec

Snappy 另一个压缩型序列化对象编码

org.redisson.client.codec.JsonJacksonMapCodec

基于Jackson的映射类使用的编码。可用于避免序列化类的信息,以及用于解决使用byte[]遇到的问题。

org.redisson.client.codec.StringCodec

纯字符串编码(无转换)

org.redisson.client.codec.LongCodec

纯整长型数字编码(无转换)

org.redisson.client.codec.ByteArrayCodec

字节数组编码

org.redisson.codec.CompositeCodec

用来组合多种不同编码在一起

自定义序列化

需求背景:

项目之前使用的RestTemplate api,RestTemplate的序列化使用的RedisSerializer接口,使用的实现类Jackson2JsonRedisSerializer。

现在改为使用RedissonClient,RedissonClient的序列化使用的Codec接口,默认实现类JsonJacksonCodec。

2种实现类序列化方式不同,而生产环境数据迁移有风险,所以需实现Codec接口,自定义RedissonClient序列化方式,替换Redisson的序列化对象JsonJacksonCodec,兼容旧数据。

目的:

兼容原有RedisTemplate Jackson2JsonRedisSerializer对象序列化数据。

分析:

RedisTemplate初始化代码:

    protected RedisTemplate<String, Object> buildRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型,类必须是非final修饰的。序列化时将对象全类名一起保存下来
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }

JsonJacksonCodec构造器初始化源码:

    public JsonJacksonCodec() {
        this(new ObjectMapper());
    }

跟踪发现底层初始化时,默认给ObjectMapper设置了一些参数:

    init(this.mapObjectMapper);

    protected void init(ObjectMapper objectMapper) {
        objectMapper.setSerializationInclusion(Include.NON_NULL);
        objectMapper.setVisibility(objectMapper.getSerializationConfig()
                                                    .getDefaultVisibilityChecker()
                                                        .withFieldVisibility(JsonAutoDetect.Visibility.ANY)
                                                        .withGetterVisibility(JsonAutoDetect.Visibility.NONE)
                                                        .withSetterVisibility(JsonAutoDetect.Visibility.NONE)
                                                        .withCreatorVisibility(JsonAutoDetect.Visibility.NONE));
        objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        objectMapper.enable(Feature.WRITE_BIGDECIMAL_AS_PLAIN);
        objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        objectMapper.enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY);
        objectMapper.addMixIn(Throwable.class, ThrowableMixIn.class);
    }

就是这些ObjectMapper的初始化参数导致对象序列化数据不兼容,所以自定义Codec,和原来ObjectMapper的初始化保持一致即可!

实现:

自定义Codec实现类:RedissonCodec

/**
 * 替换Redisson的序列化对象JsonJacksonCodec,兼容原有RedisTemplate的对象序列化。
 *
 * @author yangzihe
 * @date 2022/12/13
 */
public class RedissonCodec extends BaseCodec {

    protected final ObjectMapper mapObjectMapper;

    /**
     * @see JsonJacksonCodec
     */
    private final Encoder encoder = new Encoder() {
        @Override
        public ByteBuf encode(Object in) throws IOException {
            ByteBuf out = ByteBufAllocator.DEFAULT.buffer();
            try {
                ByteBufOutputStream os = new ByteBufOutputStream(out);
                mapObjectMapper.writeValue((OutputStream) os, in);
                return os.buffer();
            } catch (IOException e) {
                out.release();
                throw e;
            } catch (Exception e) {
                out.release();
                throw new IOException(e);
            }
        }
    };

    private final Decoder<Object> decoder = new Decoder<Object>() {
        @Override
        public Object decode(ByteBuf buf, State state) throws IOException {
            return mapObjectMapper.readValue((InputStream) new ByteBufInputStream(buf), Object.class);
        }
    };

    public RedissonCodec(ObjectMapper mapObjectMapper) {
        this(mapObjectMapper, true);
    }

    public RedissonCodec(ObjectMapper mapObjectMapper, boolean copy) {
        if (copy) {
            this.mapObjectMapper = mapObjectMapper.copy();
        } else {
            this.mapObjectMapper = mapObjectMapper;
        }
    }

    @Override
    public Decoder<Object> getValueDecoder() {
        return decoder;
    }

    @Override
    public Encoder getValueEncoder() {
        return encoder;
    }

    @Override
    public ClassLoader getClassLoader() {
        if (mapObjectMapper.getTypeFactory().getClassLoader() != null) {
            return mapObjectMapper.getTypeFactory().getClassLoader();
        }

        return super.getClassLoader();
    }
}

redis工具类

public final class RedisUtils {

    public static final Codec REDISSON_CODEC;

    static {
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型,类必须是非final修饰的。序列化时将对象全类名一起保存下来
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
        REDISSON_CODEC = new RedissonCodec(om);
    }

    private RedisUtils() {}
}

代码使用

redissonClient.getConfig().setCodec(RedisUtils.REDISSON_CODEC);

redissonClient.getSet(redisKey, RedisUtils.REDISSON_CODEC).add(object);
redissonClient.getSet(redisKey, RedisUtils.REDISSON_CODEC).remove(object);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/153391.html

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

相关文章

LeetCode二叉树经典题目(六):二叉搜索树

目录 28. LeetCode617. 合并二叉树 29. LeetCode700. 二叉搜索树中的搜索 30. LeetCode98. 验证二叉搜索树 31. LeetCode530. 二叉搜索树的最小绝对差 32. LeetCode501. 二叉搜索树中的众数 33. LeetCode236. 二叉树的最近公共祖先​ 28. LeetCode617. 合并二叉树 递归&…

Hi3861鸿蒙物联网项目实战:智能安防报警

华清远见FS-Hi3861开发套件&#xff0c;支持HarmonyOS 3.0系统。开发板主控Hi3861芯片内置WiFi功能&#xff0c;开发板板载资源丰富&#xff0c;包括传感器、执行器、NFC、显示屏等&#xff0c;同时还配套丰富的拓展模块。开发板配套丰富的学习资料&#xff0c;包括全套开发教程…

Windows11 系统打开IE浏览器的方式(完整版)

前言 大家好&#xff0c;好久不见&#xff01; 1、最近疯狂加班&#xff0c;旧电脑不太给力&#xff0c;换了新电脑&#xff0c;嘎嘎开心&#xff1b;开心之余发现新电脑是Win11系统的&#xff0c;但是IE浏览器找不到了&#xff0c;由于我的某些工作需要用到IE浏览器&#xf…

Vue2前端路由(vue-router的使用)、动态路由、路由和视图的命名以及声明式和编程式导航

目录 一、vue2的前端路由&#xff08;vue-router&#xff09; 1、路由&#xff1a;页面地址与组件之间的对应关系 2、路由方式&#xff1a;服务器端路由、前端路由 3、前端路由&#xff1a;在前端维护一组路由规则&#xff08;地址和组件之间的对应关系&#xff09;&#xf…

【UE4 第一人称射击游戏】34-制作一个简易计时器

上一篇&#xff1a;【UE4 第一人称射击游戏】33-创建一个迷你地图本篇效果&#xff1a;可以看到左上角有个简易的关卡计时器在倒计时步骤&#xff1a;打开“FPSHUD”&#xff0c;拖入一个图像控件图像选择“Timer_Backing”&#xff0c;尺寸改为4719拖入3个文本控件大小为1210字…

学习ffmpeg-录屏实现记录

项目需要一个录屏的功能&#xff0c;之前看到了一个使用Qt计时器截图avilib生成AVIffmpeg合并视频音频的方式&#xff1a;Qt C 录屏录音功能实现&#xff08;avilibffmpeg&#xff09;以及动态库生成https://blog.csdn.net/qq_35769071/article/details/125323624使用后&#x…

【.dll 没有被指定在windows上运行】

修复&#xff08;重新注册DLL&#xff09;的具体步骤如下&#xff1a; 方法一&#xff1a; 1、快捷键winr打开“运行”输入cmd,点击确定打开命令提示符窗口。 2、复制&#xff1a;for %1 in (%windir%\system32*.dll) do regsvr32.exe /s %1 命令&#xff0c;在打开的管理员…

ubuntu安装vue

首先建议使用ubuntu18.04以上的系统&#xff0c;不然会有类似fcntlGLIBC_2.28‘未定义的引用的报错 VUE官网&#xff1a;http://caibaojian.com/vue/guide/installation.html 其中安装说明只写到&#xff1a;npm install vue 我们还需要安装node.js、npm 1、安装 NVM&#xf…

Windows安装TensorRT

文章目录前言TensorRT下载TensorRT安装参考资料前言 本文将介绍Windows如何安装TensorRT。本文的基础是&#xff1a;Windows安装PytorchCUDA环境 TensorRT下载 进入官方网站&#xff1a;https://developer.nvidia.com/nvidia-tensorrt-8x-download 寻找自己对应的版本&#…

RabbitMQ之Work Queue(工作队列)

前言&#xff1a;大家好&#xff0c;我是小威&#xff0c;24届毕业生&#xff0c;曾经在某央企公司实习&#xff0c;目前在某税务公司。本篇文章将记录和分享RabbitMQ工作队列相关的知识点。 本篇文章记录的基础知识&#xff0c;适合在学Java的小白&#xff0c;也适合复习中&am…

【自学Python】Python string转bytes

Python string转bytes Python string转bytes教程 在 Python 中&#xff0c;bytes 类型和 字符串 的所有操作、使用和内置方法也都基本一致。因此&#xff0c;我们也可以实现将字符串类型转换成 bytes 类型。 Python string转bytes方法 如果字符串内容都是 ASCII 字符&#…

从0到1完成一个Vue后台管理项目(十六、后端分页方法以及分页组件的封装以及复用)

往期 从0到1完成一个Vue后台管理项目&#xff08;一、创建项目&#xff09; 从0到1完成一个Vue后台管理项目&#xff08;二、使用element-ui&#xff09; 从0到1完成一个Vue后台管理项目&#xff08;三、使用SCSS/LESS&#xff0c;安装图标库&#xff09; 从0到1完成一个Vu…

C++STL——list类与模拟实现

Listlistlist的常用接口模拟实现完整代码list与vector的区别list list是一个带头双向循环链表。 list文档介绍&#xff1a;https://legacy.cplusplus.com/reference/list/list/ list因为是链表结构&#xff0c;所以没有 [] 去访问数据的方式&#xff0c;只有用迭代器&#xff…

第十六届中国大数据技术大会五大分论坛顺利举办!

1月8日下午&#xff0c;由苏州市人民政府指导、中国计算机学会主办、苏州市吴江区人民政府支持&#xff0c;CCF大数据专家委员会、苏州市吴江区工信局、吴江区东太湖度假区管委会、苏州市吴江区科技局、苏州大学未来科学与工程学院及DataFounain数联众创联合承办的第十六届中国…

基于java springboot+mybatis学生学科竞赛管理管理系统设计和实现

基于java springbootmybatis学生学科竞赛管理管理系统设计和实现 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言…

10.Isaac教程--在Docker中通过模拟训练目标检测

在Docker中通过模拟训练目标检测 文章目录在Docker中通过模拟训练目标检测怎么运行的主机设置硬件要求软件要求NGC Docker 注册表设置第一次运行数据集生成配置您的工作区Jupyter 变量设置开始训练添加您自己的 3D 模型故障排除接下来人工智能中的一个常见问题是训练样本的数据…

02【Http、Request】

文章目录02【Http、Request】一、HTTP协议1.1 HTTP协议概述1.1.1 HTTP协议的概念1.1.2 HTTP协议的特点&#xff1a;2.1 HTTP请求的组成2.1.1 请求行2.1.2 请求头2.1.3 请求体二、HttpServletRequest对象2.1 HttpServletRequest对象简介2.2 HttpServletRequest的使用2.2.1 请求行…

Redis未授权访问漏洞(三)Redis写入反弹连接定时任务

前言 系列文章 Redis未授权访问漏洞(一)先导篇 Redis未授权访问漏洞(二)Webshell提权篇 Redis写入反弹连接任务 环境准备 攻击机&#xff1a; Centos7 IP:192.168.142.44 靶机&#xff1a;Centos7 IP:192.168.142.66 我们先来回顾一下corntab定时任务的一些基本命令&#xf…

python数据分析及可视化(二十)Power BI的可视化制作以及A股上市公司数据分析

可视化制作 通过图表展示如何用Power BI 制作可视化的图表&#xff0c;来展示可视的数据内容。 柱形图 用水平的柱子来表示不同分类数据的大小&#xff0c;类似于条形图&#xff0c;相当于竖着的条形图。堆积柱形图是不同的序列数据都堆积在一个柱子上&#xff0c;簇状柱形图…

【Spring源码】20. MergedBeanDefinitionPostProcessor修改/合并bean定义

随后进入applyMergedBeanDefinitionPostProcessors()方法applyMergedBeanDefinitionPostProcessors()方法中调用MergedBeanDefinitionPostProcessor后置处理器修改/合并bean定义 进入bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName) 从源码中可以看到&#xff0…