首先,提问时请准确。
你的Key 类甚至不是有效的Java。 Key 类本身甚至无法按原样编译。
在这种情况下,构造函数 (JsonWebKey) 是 1) 没有以类 (Key) 命名,以及 2) 不能有 2 个没有 arg 构造函数。
我假设第二个构造函数是:
public Key(String id, Jwk jwk) {
this.id = id;
this.jwk = jwk;
}
我猜是构造函数名称错误,或者可能是某些 [静态] 内部类的一部分??
Never-the-less,假设您使用 Spring Boot for Apache Geode(和 VMware Tanzu (Pivotal) GemFire),又名SBDG(请参阅here;如果您不使用 SBDG,那么您应该使用!),并且由于 SBDG enables GemFire/Geode PDX serialization by default,那么 SBDG 在 Spring Data for Apache 的帮助下Geode(和 VMware Tanzu GemFire),又名 SDG(在其上构建 SBDG,以及核心 Spring 框架,Spring Data 和 Spring Boot)将为您处理这些序列化问题,您无需付出额外的努力。参见对应的 SDGdocumentation。
举个例子,我写了这个test class,它驻留在这个package中,来演示一下。
默认情况下,测试类使用 PDX 序列化 configured with Spring,使用 test configuration。基于 Spring 的配置类是here。 other test configuration classes 仅通过适当的test Spring profile configured 启用。
此测试的模型类是model 子包中的CompositeValue class。
如您所见,该类有2 primary constructors。我还声明了一个commented-out, default, public no-arg constructor,我将在下面进一步解释。
这个CompositeValue 模型类是经过精心设计的。你会注意到它(大部分)是不可变的。
我使用 Spring Data CrudRepository(参见 here)在 GemFire/GeodeRegion(“Values") 然后检索它 (findBy..)。 “Values”区域必须是 PARTITION 区域(请参阅 here),因为 PARTITION 区域以序列化形式存储值,在我们的例子中,PDX 序列化。
使用 Spring 配置,test 运行并成功通过!春天正在做所有繁重的工作!
如果您没有充分利用 Spring,那么您(很可能)会遇到问题,除非您知道自己在使用 GemFire/Geode 做什么。
开箱即用的 GemFire/Geode PDX 序列化具有一定的局限性。请参阅documentation。具体见here。
例如,如果您使用的是 GemFire/Geode 的 ReflectionBasedAutoSerializer 类(Javadoc,documentation;我怀疑您是)而不是 Spring,那么它需要您的应用程序域对象(模型类/实体)有一个默认的、公共的无参数构造函数。
这与不可变、有效不可变和大部分不可变的类背道而驰,因为那时您无法使用构造函数适当地初始化类,这在高并发、多线程上下文(如 GemFire/Geode)中至关重要。
你可以通过启用我写的“gemfire”配置文件in the example test class来查看尝试使用GemFire/Geode的ReflectionBasedAutoSerializer的效果,配置为here。
没有commented-out, default, public no-arg constructor,测试将无法通过。
使用 Apache Geode 1.13.4 时,出现以下错误:
2021-11-01 11:53:08,720 WARN ode.pdx.internal.AutoSerializableManager: 274 - Class
io.stackoverflow.questions.spring.geode.serialization.pdx.model.CompositeValue
matched with '.*' cannot be auto-serialized due to missing public no-arg constructor.
Will attempt using Java serialization.
但是,即使使用 Java 序列化(GemFire/Geode 备份序列化策略),测试也会导致失败:
Caused by: java.io.NotSerializableException: io.stackoverflow.questions.spring.geode.serialization.pdx.model.CompositeValue
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at org.apache.geode.internal.InternalDataSerializer.writeSerializableObject(InternalDataSerializer.java:2184)
at org.apache.geode.internal.InternalDataSerializer.basicWriteObject(InternalDataSerializer.java:2058)
at org.apache.geode.DataSerializer.writeObject(DataSerializer.java:2839)
at org.apache.geode.internal.cache.CachedDeserializableFactory.calcSerializedSize(CachedDeserializableFactory.java:245)
... 60 common frames omitted
好吧,java.io.NotSerializableException 被抛出是因为CompositeValue 类(故意)没有实现java.io.Serialiable 接口。
为什么是故意的?因为你不能在你不拥有的类上实现java.io.Serializable,这在使用 3rd 方库及其类时是正确的。即使在我的情况下我们拥有CompositeValue,但我要说明一点,因为在您的情况下,您并不拥有Jwk。
因此,我们不仅不能(大部分/有效地)使用不可变类,我们也不能依赖于 GemFire/Geode 中的默认序列化机制。
当然,我们可以通过实现自定义PdxSerializer 来处理这个问题,这是documentation 中的第二个策略(在“Procedure”下,第1 步,“Serializing your Domain Object with a PdxSerializer”)。
如果我们在我编写的示例测试中再次将活动的 Spring 配置文件 change 设置为“gemfire-custom-pdxserializer”,那么测试将通过。
但是,它的价格很高!请参阅necessary configuration 以进行此安排。
在我们的例子中,我们只有 1 个这样的模型/实体类来构建自定义 PdxSerializer 。但是,想象一下,如果我们有数百个类要处理。
更糟糕的是,GemFire/Geode 只允许将单个 PdxSerializer 注册到 Singleton GemFire/Geode 缓存,这意味着您只能拥有 1 个。现在您必须依赖 Composite Software Design Pattern 来组合多个 @ 987654379@ 处理所有需要序列化的应用程序域模型类型所必需的。虽然这很优雅,但您必须为每个应用程序模型/实体类型构建一个自定义 PdxSerializer。当然,您可以将所有类型处理融入到 1 个PdxSerializer 实现中,但这会很快变得丑陋!
最后,您的应用程序模型/实体类型可以实现 GemFire/Geode 的 PdxSerializable 接口 (Javadoc)。这并不比java.io.Serializable 好,并且(再次)不适用于您不拥有的类型。它还将您的应用程序与 GemFire/Geode 耦合,这就是我没有演示这种方法的原因,因为它应该被视为一种反模式。
使用 SDG 的 MappingPdxSerializer,SBDG 会为您自动配置(默认情况下),您无需执行上述任何操作。 SBDG 默认自动配置 PDX(不需要 SDG @EnablePdx 注释),并且对您的应用程序域对象(模型)/实体类没有特殊要求。
但是,如果您的实体类中有超过 1 个 构造函数,那么您需要指定 1 个构造函数作为主要的持久性构造函数。在CompositeValue 类中,这个constructor 被指定为使用Spring Data 的@PersistenceConstructor 注释的主要持久性构造函数,SDG 的MappingPdxSerializer 在反序列化和构造应用程序域对象模型类型时会考虑到这一点。
如果你的类中只有 1 个构造函数,那么你甚至不需要在唯一的构造函数上声明 @PersistenceConstructor 注释。也就是说,如果CompositeValue 中的other constructor 不存在,那么这个constructor 上的@PersistenceConstructor 注释就没有必要了。 SD[G] 可以解决。
出于学习目的,请随意使用我的示例测试。