尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Redisson 对象引用(Object References):让 Redis 对象像 Java 对象一样互相嵌套
Redisson 对象引用Object References让 Redis 对象像 Java 对象一样互相嵌套【免费下载链接】redissonRedisson: Valkey Redis Java Client and Real-Time Data Platform. Sync/Async/RxJava/Reactive API. Over 50 Valkey and Redis based Java objects and services: Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, Map Reduce, Bloom filter, Spring, Tomcat, Scheduler, JCache API, Hibernate, RPC, local cache..项目地址: https://gitcode.com/GitHub_Trending/re/redisson导读本篇技术指南讲解 Redisson 中一个独特且强大的能力——对象引用Object References它允许你将一个 Redisson 分布式对象如 Map、Set、List、Bucket、Queue 等作为另一个 Redisson 对象的元素或键值直接存放甚至支持循环引用无需任何手工序列化或持久化操作。读完本文你将掌握对象引用的声明方式、循环引用与免持久化行为的原理、底层存储结构以及如何通过源码与配置理解其工作机制。一、什么是 Redisson 对象引用在常规的 Redis 客户端编程中如果我们想把一个对象存入另一个对象通常的做法是把前者序列化为字节数组、JSON 字符串或 Hash 结构再塞进去。这意味着被存入的对象一旦内容变化外层容器里的数据并不会自动更新必须重新序列化并再次写入。Redisson 提供了一种不同的模型——引用。在 object-references.md 中明确指出Its possible to use a Redisson object inside another Redisson object in any combination. In this case a special reference object will be used and handled by Redisson.也就是说任意组合下都可以把 Redisson 对象放进另一个 Redisson 对象中。此时 Redisson 并不会把被嵌套对象的全部内容序列化进去而是写入一个特殊的引用对象reference object由 Redisson 在内部识别并处理。外层对象里存放的只是一条指针而非数据快照。二、快速上手嵌套对象声明与使用官方文档给出了一个经典示例展示了三层嵌套的 Map/Set/ListRMapRSetRList, RListRMap map redisson.getMap(myMap); RSetRList set redisson.getSet(mySet); RListRMap list redisson.getList(myList); map.put(set, list);这段代码说明了三个要点类型可以任意组合RMap的键可以是RSetRList值可以是RListRMapRSet的元素可以是RListRList的元素又可以是RMap。嵌套深度不限、组合方式不限。使用方式与普通 Java 集合一致声明、put、add等方法调用与java.util集合毫无差别开发者不需要关心底层是哪个 Redis 数据结构。对象与对象之间通过引用关联map.put(set, list)之后set与list本身在 Redis 中仍然是独立对象只是map中记录了指向它们的引用。从源码结构看这种Java 接口 → Redisson 实现的映射关系被集中定义在 RedissonObjectBuilder.java 的静态映射表中L50-L63SUPPORTED_CLASS_MAPPING.put(SortedSet.class, RedissonSortedSet.class); SUPPORTED_CLASS_MAPPING.put(Set.class, RedissonSet.class); SUPPORTED_CLASS_MAPPING.put(ConcurrentMap.class, RedissonMap.class); SUPPORTED_CLASS_MAPPING.put(Map.class, RedissonMap.class); SUPPORTED_CLASS_MAPPING.put(BlockingDeque.class, RedissonBlockingDeque.class); SUPPORTED_CLASS_MAPPING.put(Deque.class, RedissonDeque.class); SUPPORTED_CLASS_MAPPING.put(BlockingQueue.class, RedissonBlockingQueue.class); SUPPORTED_CLASS_MAPPING.put(Queue.class, RedissonQueue.class); SUPPORTED_CLASS_MAPPING.put(List.class, RedissonList.class);因此RMapRSetRList, RListRMap这样的嵌套声明最终都会被映射到具体的RedissonXxx实现类上由统一的对象构建器负责引用与还原。三、循环引用突破序列化的天然限制如果采用传统的整体序列化方案下面这段代码几乎必然导致无限递归或栈溢出——因为set包含list而list又包含mapmap.put(set, list); // With the help of the special reference object, we can even create a circular // reference which is impossible to achieve if we were to serialize its content set.add(list); list.add(map);Redisson 文档明确说明借助特殊引用对象可以创建循环引用circular reference而如果对内容做序列化这将是无法实现的。原因很简单引用是扁平的。list.add(map)时list中存放的只是指向map的一条引用记录set.add(list)、map.put(set, list)同理。三者互相指向但每条引用记录的体积都是固定的不存在递归展开的过程因此天然支持环状结构。对应的测试用例可以在 RedissonReferenceTest.java 的testBatch()中看到三个 Bucket 互相引用b1→b2→b3→b1后通过 Batch 读取并断言三者名称分别为 b2、b3、b1验证了循环引用在写入与读取两个方向上都成立。四、引用式行为无需手动重新保存原文档强调了一个容易被忽视、但极其重要的行为差异As you may have noticed there is no need to re save/persist the map object after its elements have changed. Because it does not contain any value but merely a reference, this makes Redisson objects behaves much more like standard Java objects. In effect, making Redis or Valkey becomes part of JVMs memory rather than just a simple repository.这意味着改动被引用对象后外层容器无需重新写入。例如set.add(list)之后即使后续往list里再添加元素set中依然能看到最新的list因为set里保存的是引用而不是旧数据快照。行为更像标准 Java 对象RMap、RSet、RList之间的引用关系与 JVM 堆上的对象图一致改动是穿透的。体验上Redis/Valkey 更像 JVM 内存的一部分而不是一个需要显式同步的外部仓储。测试用例testWithList()也印证了这一行为RSetRBucketString b1 redisson.getSet(set); RBucketString b2 redisson.getBucket(bucket); b1.add(b2); b2.set(test1); Assertions.assertEquals(b2.get(), b1.iterator().next().get());先把b2加入b1再修改b2的内容读取b1时得到的是修改后的最新值。五、底层原理RedissonReference 与对象构建器引用机制的核心由两个组件协同完成引用载体RedissonReference与转换器RedissonObjectBuilder。5.1 引用载体RedissonReferenceRedissonReference.javaL32-L73是实际被写入 Redis 的引用对象它只包含三个字段字段含义type被引用对象的类型类全名用于读回时重建正确的 Redisson 对象keyName被引用对象在 Redis 中的 key 名称即指针指向的位置codec被引用对象使用的编解码器类名为null时表示使用全局默认 codec其构造函数对可被引用的类型做了严格校验L48-L53只有RObject、RLiveObject标注REntity的类型、RObjectReactive、RObjectRx及其子类才允许被引用否则抛出IllegalArgumentException。同时RedissonReference提供了同步/Reactive/Rx 三套读回接口getType()、getReactiveType()、getRxJavaType()这意味着同一个引用可以在三种编程模型中互相转换。测试用例testNormalToReactive()演示了先用同步 Batch 写入引用链再用 Reactive Batch 读取并正确还原的过程。5.2 转换器RedissonObjectBuilderRedissonObjectBuilder.java 负责对象 ↔ 引用的双向转换toReference(Object)L250-L295写入时调用。判断对象是否为RObject/RObjectReactive/RObjectRx且非RLiveObject是则提取其接口类型、key 名称与 codec构造RedissonReference若是RLiveObject则通过NamingScheme解析实体 id 生成引用其他普通 Java 对象返回null表示不参与引用转换。fromReference(RedissonReference, ReferenceType)L185-L248读取时调用。根据引用中的type、keyName与codec通过反射调用redisson.getXxx(name)或redisson.getXxx(name, codec)重建出真实的分布式对象。tryHandleReference(Object, ReferenceType)L322-L430递归处理读回结果把嵌套在List、Set、Map、ScoredEntry、MapScanResult等容器内部的RedissonReference逐个还原为真实对象。5.3 编码拦截点CommandAsyncService引用转换是在命令编码阶段被自动触发的。在 CommandAsyncService.java 的encode、encodeMapKey、encodeMapValue三个方法L949-L995中if (isRedissonReferenceSupportEnabled()) { RedissonReference reference getObjectBuilder().toReference(value); if (reference ! null) { value reference; } }写入任何数据前都会先尝试把对象转成RedissonReference成功则写入引用失败返回null则按普通值序列化。这就解释了为什么map.put(set, list)、set.add(list)等调用无需额外代码——引用转换对所有写入路径透明生效。5.4 codec 的保留与还原引用中记录了 codec 类名读回时通过 DefaultReferenceCodecProvider.java 按类名查找/实例化对应的Codec内部用ConcurrentHashMap做实例缓存。测试用例shouldUseDefaultCodec()验证了用Kryo5Codec配置客户端写入引用后用另一个客户端读回得到的对象依然使用相同的 codec 实例且内容正确还原。六、存储布局底层 Redis 数据结构原文档明确指出上述示例最终在 Redis/Valkey 中只产生三个 keyOne Redis HASH, one Redis SET and one Redis LIST will be created in the example above.即Java 对象底层 Redis 结构keyRMapRSetRList, RListRMap mapHASHHSETmyMapRSetRList setSETSADDmySetRListRMap listLISTRPUSHmyList嵌套元素不会展开成额外的 key——set里的list只是指向myList的引用记录。测试用例testWithList()中的断言redisson.getKeys().count() 2也印证了这一点写入一个 SET 和一个 Bucket 引用Redis 中只有两个 key不存在额外的序列化副本。这也意味着引用不会复制数据只会增加一条轻量记录。七、适用范围与能力矩阵从 RedissonReferenceTest.java 可以看出引用机制覆盖了绝大多数 Redisson 对象与容器包括基础对象RBucket、RBitSet、RMapCache集合容器RSet、RSetCache、RList含subList、RQueue、RDelayedQueue、RPriorityQueue排序与地理RScoredSortedSet含ScoredEntry值引用、RGeo多值映射RListMultimap、RSetMultimap本地缓存RLocalCachedMapMap 的各类读取 APIreadAllMap、readAllEntrySet、readAllValues、readAllKeySet中嵌套引用的还原键与值均可引用如RMapRBucketString, RSetCacheRBucketStringmap 的键和值都能是引用Live ObjectRLiveObject实体也可被引用如RBucketRLiveObject读回时自动还原为 Live Object 代理此外引用还与Batch批处理完全兼容见testBatch()并且 Reactive 客户端可以正确读回同步客户端写入的引用见testNormalToReactive()。八、配置开关referenceEnabled引用功能默认开启可以通过 Config.java 中的配置项控制L75、L265-L278private boolean referenceEnabled true; public boolean isReferenceEnabled() { return referenceEnabled; } public void setReferenceEnabled(boolean redissonReferenceEnabled) { this.referenceEnabled redissonReferenceEnabled; }在 CommandAsyncService.java 中引用转换的前提是isRedissonReferenceSupportEnabled()即objectBuilder ! null。当业务场景不需要对象嵌套、希望获得最纯粹的值序列化语义时可以关闭该特性默认开启时所有写入路径都会先尝试引用转换对普通对象无影响因为toReference返回null。九、总结Redisson 的对象引用特性把分布式对象之间的关联从复制数据提升为建立引用任意嵌套Map/Set/List/Queue/Bucket 等对象可以任意组合互相包含声明与使用方式与标准 Java 集合一致。支持循环引用引用记录是扁平的环状对象图不会引发递归序列化问题。免手动持久化外层容器保存的是引用被引用对象的内容变更自动穿透可见使 Redis/Valkey 更接近 JVM 内存的延伸。底层透明写入时由RedissonObjectBuilder与CommandAsyncService自动完成对象 →RedissonReference转换读取时自动还原底层只产生对应的 HASH/SET/LIST 等原生结构不产生数据副本。可配置、可扩展通过Config.setReferenceEnabled控制开关同时兼容 Batch、Reactive/Rx 客户端与 Live Object。如果需要进一步了解相关主题可继续阅读 分布式对象、数据序列化 以及 Live Object 文档。【免费下载链接】redissonRedisson: Valkey Redis Java Client and Real-Time Data Platform. Sync/Async/RxJava/Reactive API. Over 50 Valkey and Redis based Java objects and services: Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, Map Reduce, Bloom filter, Spring, Tomcat, Scheduler, JCache API, Hibernate, RPC, local cache..项目地址: https://gitcode.com/GitHub_Trending/re/redisson创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED

相关推荐

渐进式披露重构实战:Cloudflare Zaraz 参考文档 5 文件分层体系在 Codex Skills 目录中的设计与落地

渐进式披露重构实战:Cloudflare Zaraz 参考文档 5 文件分层体系在 Codex Skills 目录中的设计与落地

渐进式披露重构实战:Cloudflare Zaraz 参考文档 5 文件分层体系在 Codex Skills 目录中的设计与落地 【免费下载链接】skills Skills Catalog for Codex 项目地址: https://gitcode.com/GitHub_Trending/skills4/skills 本篇围绕 skills/.curated/cloudflare…

📅 2026/9/12 17:03:28
基于51单片机的TLC2543数据采集Proteus仿真实战

基于51单片机的TLC2543数据采集Proteus仿真实战

简介:基于51单片机的12位AD数据采集完整设计方案,适合单片机初学者和Proteus仿真爱好者。资源围绕TLC2543模拟转换器、44键盘、8位LED显示器和两个发光二极管,实现通过键盘输入通道号并完成11路模拟通道的数据采集,在LED上同步显示…

📅 2026/9/12 17:03:28
文件是怎么变成预览页的:kkFileView 核心链路深度拆解

文件是怎么变成预览页的:kkFileView 核心链路深度拆解

文件是怎么变成预览页的:kkFileView 核心链路深度拆解 【免费下载链接】kkFileView Universal File Online Preview Project based on Spring-Boot 项目地址: https://gitcode.com/GitHub_Trending/kk/kkFileView kkFileView 是一个基于 Spring Boot 的通用文…

📅 2026/9/12 17:03:28
MORE NEWS

更多资讯

📰

dcode 如何用 -r 恢复历史会话并查看线程列表?

dcode 如何用 -r 恢复历史会话并查看线程列表? 【免费下载链接】deepagents The batteries-included agent harness. 项目地址: https://gitcode.com/GitHub_Trending/de/deepagents deepagents-code(CLI 命令名为 dcode)是 deepagent…

📰

用南瓜数据重做 Web App:在 ML-For-Beginners 中替换模型并部署

用南瓜数据重做 Web App:在 ML-For-Beginners 中替换模型并部署 【免费下载链接】ML-For-Beginners 12 weeks, 26 lessons, 52 quizzes, classic Machine Learning for all 项目地址: https://gitcode.com/GitHub_Trending/ml/ML-For-Beginners 导读 本篇文…

📰

docker-minecraft-server CurseForge模组包自动安装失败速查:4步彻底解决

docker-minecraft-server CurseForge模组包自动安装失败速查:4步彻底解决 【免费下载链接】docker-minecraft-server Docker image that provides a Minecraft Server for Java Edition that automatically installs/upgrades versions, modloaders, modpacks and m…

📰

VPI中SOA光放大仿真:参数映射、增益噪声提取与发散排查

简介:这是一个面向光纤通信与光子学研究者的半导体光放大器(SOA)MATLAB仿真资源,压缩包内仅含1个m源码文件,大小约1KB,基于VPI仿真思路构建,可复现SOA的增益、饱和、自发辐射噪声以及四波混频等…

📰

3 步替换默认 malloc:mimalloc 低延迟内存分配器接入实战

3 步替换默认 malloc:mimalloc 低延迟内存分配器接入实战 【免费下载链接】mimalloc mimalloc is a compact general purpose allocator with excellent performance. 项目地址: https://gitcode.com/GitHub_Trending/mi/mimalloc mimalloc 是微软开源&#…

📰

C语言文件操作全解析:从基础到高级技巧

1. C语言文件操作基础概念在C语言中,文件操作是程序与外部存储介质交互的重要方式。文件读取操作主要涉及三个核心步骤:打开文件、读取内容和关闭文件。这三个步骤构成了文件处理的基本流程,任何文件操作都离不开这个基本框架。文件指针&…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬