编解码器
Spring Integration 4.2 版引入了 Codec
抽象。编解码器将对象编码和解码为 byte[]
。它们提供了 Java 序列化的替代方案。其中一个优点是,通常对象不需要实现 Serializable
。我们提供了一种使用 Kryo 进行序列化的实现,但你可以提供自己的实现以用于以下任何组件:
-
编码有效负载转换器
-
解码转换器
-
编解码消息转换器
编码有效负载转换器
此转换器通过使用编解码器将有效负载编码为 byte[]
。它不会影响消息头。
更多信息请参见 Javadoc。
DecodingTransformer
此转换器通过使用编解码器对 byte[]
进行解码。它需要配置一个对象应被解码成的 Class
(或解析为一个 Class
的表达式)。如果结果对象是一个 Message<?>
,则传入的标头不会被保留。
更多信息请参见 Javadoc。
CodecMessageConverter
某些端点(例如 TCP 和 Redis)没有消息头的概念。它们支持使用 MessageConverter
,并且可以使用 CodecMessageConverter
将消息转换为 byte[]
或从 byte[]
转换以进行传输。
更多信息请参见 Javadoc。
Kryo
目前,这是唯一的 Codec
实现,并且它提供了两种类型的 Codec
:
-
PojoCodec
:用于转换器中 -
MessageCodec
:用于CodecMessageConverter
中
框架提供了几个自定义序列化器:
-
文件序列化器
-
消息头序列化器
-
可变消息头序列化器
第一种可以通过使用 FileKryoRegistrar
初始化它来与 PojoCodec
一起使用。第二种和第三种是与 MessageCodec
一起使用的,而 MessageCodec
是通过 MessageKryoRegistrar
初始化的。
自定义 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 注册该类,这在某些情况下可能使这种方法不够理想。