Java应用使用Infinispan共享Object graph时引用丢失问题如何解决
Infinispan共享对象图引用丢失问题解决方案
该引用丢失问题本质是Infinispan默认按值存储的特性导致的——所有存入缓存的对象都会经过序列化/反序列化流程,每次从缓存读取到的都是独立的新实例,Java堆内的原生对象引用自然无法跨序列化边界保留,可根据部署场景选择以下解决方案:
适用同JVM场景的方案
- 开启按引用存储模式
如果是单节点部署或者嵌入式模式下同个JVM内共享对象图,可以直接开启缓存的按引用存储配置,关闭序列化流程:
配置示例(XML格式):
配置生效后,缓存内存储的是对象的直接引用,更新对象时所有关联引用都会自动生效,无需额外处理。注意该方案仅适用于同JVM场景,多节点分布式场景下无法使用。<local-cache name="objectGraphCache"> <encoding media-type="application/x-java-object" /> <memory storage="HEAP" /> </local-cache>
适用分布式多节点场景的方案
重构对象图为外键关联模式
分布式场景下序列化流程不可避免,此时需要把原生对象引用替换为业务主键/缓存键的关联:- 所有需要被多个对象引用的公共实体,单独作为缓存条目存入Infinispan,分配唯一的缓存键(比如
user:1001) - 其他持有该实体引用的对象,不再直接存储对象实例,改为存储对应的缓存键
- 需要访问关联对象时,实时根据键从缓存中查询最新实例
该方案是分布式场景下的标准做法,兼容性最好,同时还能避免对象图序列化时的深度递归导致的性能问题、栈溢出问题。
- 所有需要被多个对象引用的公共实体,单独作为缓存条目存入Infinispan,分配唯一的缓存键(比如
启用JBoss Marshalling序列化保留内部引用
可以开启Infinispan的store-as-binary配置的引用保留选项,搭配JBoss Marshalling序列化器实现引用的自动还原:
配置示例:<distributed-cache name="graphCache"> <encoding media-type="application/x-jboss-marshalling" /> <memory storage="OFF_HEAP" /> <store-as-binary keys="false" values="true" /> </distributed-cache>搭配JBoss Marshalling序列化器时,序列化过程会自动识别同一个对象图内的重复引用,反序列化时会还原引用关联,避免同一个对象被反序列化为多个实例。注意该方案仅能保证单次存入的同一个对象图内部的引用完整性,如果你多次更新单独的公共对象,还是需要配合外键关联模式使用。
搭配ORM框架自动处理关联
如果已经使用了Hibernate OGM搭配Infinispan作为存储,可以直接启用实体关联映射功能,框架会自动处理关联对象的懒加载和引用更新,无需手动处理键关联。
通用注意事项
- 大型对象图不建议整图序列化存入同一个缓存键,会导致更新成本极高,每次修改任意节点都需要重新序列化整个对象图,性能损耗非常大,建议拆分为多个独立缓存条目通过键关联。
- 多节点更新共享对象时需要做好并发控制,配置合适的锁策略或者事务模式,避免更新丢失。
内容的提问来源于stack exchange,提问作者Nehemia Litterat
相关产品推荐
相关产品推荐

