此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Integration 6.5.1! |
Codec
Spring Integration 的 4.2 版引入了Codec
抽象化。
编解码器对对象进行编码和解码byte[]
.
它们提供了 Java 序列化的替代方案。
一个优点是,通常,对象不需要实现Serializable
.
我们提供了一种使用 Kryo 进行序列化的实现,但您可以提供自己的实现以用于以下任何组件:
-
EncodingPayloadTransformer
-
DecodingTransformer
-
CodecMessageConverter
EncodingPayloadTransformer
此转换器将有效负载编码为byte[]
通过使用编解码器。
它不会影响邮件头。
有关更多信息,请参阅 Javadoc。
DecodingTransformer
该转换器解码byte[]
通过使用编解码器。
它需要配置Class
对象应解码到的表达式(或解析为Class
).
如果生成的对象是Message<?>
,则不会保留入站标头。
有关更多信息,请参阅 Javadoc。
CodecMessageConverter
某些端点(例如 TCP 和 Redis)没有消息头的概念。
他们支持使用MessageConverter
和CodecMessageConverter
可用于将消息转换为byte[]
用于传输。
有关更多信息,请参阅 Javadoc。
克里奥
目前,这是唯一的实现Codec
,它提供了三种Codec
:
-
PojoCodec
:用于转换器 -
MessageCodec
:用于CodecMessageConverter
-
CompositeCodec
:用于转换器
该框架提供了几个自定义序列化程序:
-
FileSerializer
-
MessageHeadersSerializer
-
MutableMessageHeadersSerializer
第一个可以与PojoCodec
通过使用FileKryoRegistrar
.
第二个和第三个与MessageCodec
,它使用MessageKryoRegistrar
.
复合编解码器
这CompositeCodec
是一种编解码器,它将多个编解码器组合成一个编解码器,将编码和解码作委托给适当的特定于类型的编解码器。
此实现将对象类型与其适当的编解码器相关联,同时为未注册的类型提供回退默认编解码器。
下面可以看到一个示例实现:
void encodeDecodeSample() {
Codec codec = getFullyQualifiedCodec();
//Encode and Decode a Dog Object
Dog dog = new Dog("Wolfy", 3, "woofwoof");
dog = codec.decode(
codec.encode(dog),
Dog.class);
System.out.println(dog);
//Encode and Decode a Cat Object
Cat cat = new Cat("Kitty", 2, 8);
cat = codec.decode(
codec.encode(cat),
Cat.class);
System.out.println(cat);
//Use the default code if the type being decoded and encoded is not Cat or dog.
Animal animal = new Animal("Badger", 5);
Animal animalOut = codec.decode(
codec.encode(animal),
Animal.class);
System.out.println(animalOut);
}
/**
* Create and return a {@link CompositeCodec} that associates {@code Dog} and {@code Cat}
* classes with their respective {@link PojoCodec} instances, while providing a default
* codec for {@code Animal} types.
* <p>
* @return a fully qualified {@link CompositeCodec} for {@code Dog}, {@code Cat},
* and fallback for {@code Animal}
*/
static Codec getFullyQualifiedCodec() {
Map<Class<?>, Codec> codecs = new HashMap<Class<?>, Codec>();
codecs.put(Dog.class, new PojoCodec(new KryoClassListRegistrar(Dog.class)));
codecs.put(Cat.class, new PojoCodec(new KryoClassListRegistrar(Cat.class)));
return new CompositeCodec(codecs, new PojoCodec(
new KryoClassListRegistrar(Animal.class)));
}
// Records that will be encoded and decoded in this sample
record Dog(String name, int age, String tag) {}
record Cat(String name, int age, int lives) {}
record Animal(String name, int age){}
在某些情况下,单一类型的对象可能会返回多个编解码器。
在这些情况下,一个IllegalStateException
被抛出。
此类使用ClassUtils.findClosestMatch 为给定对象类型选择适当的编解码器。
当多个编解码器匹配一个对象类型时,ClassUtils.findClosestMatch 提供failOnTie 选择。
如果failOnTie 是false ,它将返回任何一个匹配的编解码器。
如果failOnTie 是true 并且多个编解码器匹配,它会抛出一个IllegalStateException .
CompositeCodec' 集failOnTie 自true ,因此如果多个编解码器匹配,则IllegalStateException 被抛出。 |
自定义 Kryo
默认情况下,Kryo 将未知的 Java 类型委托给其FieldSerializer
. Kryo 还为每个基元类型注册默认序列化器,以及String
,Collection
和Map
.FieldSerializer
使用反射来导航对象图。一种更有效的方法是实现一个自定义序列化器,该序列化器知道对象的结构,并且可以直接序列化选定的基元字段。以下示例显示了这样的序列化器:
public class AddressSerializer extends Serializer<Address> {
@Override
public void write(Kryo kryo, Output output, Address address) {
output.writeString(address.getStreet());
output.writeString(address.getCity());
output.writeString(address.getCountry());
}
@Override
public Address read(Kryo kryo, Input input, Class<Address> type) {
return new Address(input.readString(), input.readString(), input.readString());
}
}
这Serializer
接口公开Kryo
,Input
和Output
,提供对包含哪些字段和其他内部设置的完全控制,如 Kryo 文档中所述。
注册自定义序列化器时,您需要一个注册 ID。注册 ID 是任意的。但是,在我们的例子中,必须显式定义 ID,因为分布式应用程序中的每个 Kryo 实例都必须使用相同的 ID。Kryo 建议使用较小的正整数并保留少量 ID(值 < 10)。Spring Integration 目前默认使用 40、41 和 42(对于前面提到的文件和消息头序列化器)。我们建议您从 60 开始,以允许在框架中进行扩展。您可以通过配置前面提到的注册器来覆盖这些框架默认值。 |
使用自定义 Kryo 序列化器
如果您需要自定义序列化,请参阅 Kryo 文档,因为您需要使用本机 API 来进行自定义。有关示例,请参阅org.springframework.integration.codec.kryo.MessageCodec
实现。
实现 KryoSerializable
如果您有write
访问域对象源代码,您可以实现KryoSerializable
如此处所述。在这种情况下,该类本身提供了序列化方法,不需要进一步配置。然而,基准测试表明,这不如显式注册自定义序列化程序那么有效。以下示例显示了自定义 Kryo 序列化程序:
public class Address implements KryoSerializable {
@Override
public void write(Kryo kryo, Output output) {
output.writeString(this.street);
output.writeString(this.city);
output.writeString(this.country);
}
@Override
public void read(Kryo kryo, Input input) {
this.street = input.readString();
this.city = input.readString();
this.country = input.readString();
}
}
您还可以使用此技术包装 Kryo 以外的序列化库。
使用@DefaultSerializer
注解
Kryo 还提供了一个@DefaultSerializer
注释,如此处所述。
@DefaultSerializer(SomeClassSerializer.class)
public class SomeClass {
// ...
}
如果您有write
访问域对象,这可能是指定自定义序列化程序的更简单方法。
请注意,这不会向 ID 注册类,这可能会使该技术在某些情况下无济于事。