编解码器

Spring Integration 4.2 版本引入了Codec抽象。Codec 将对象编码和解码为byte[]。它们提供了 Java 序列化的替代方案。一个优点是,通常情况下,对象不需要实现Serializable接口。我们提供了一个使用Kryo进行序列化的实现,但您也可以提供自己的实现,用于以下任何组件:

  • EncodingPayloadTransformer

  • DecodingTransformer

  • CodecMessageConverter

EncodingPayloadTransformer

此转换器使用 codec 将有效负载编码为byte[]。它不会影响消息头。

更多信息,请参见Javadoc

DecodingTransformer

此转换器使用 codec 解码byte[]。它需要配置要将对象解码到的Class(或解析为Class的表达式)。如果结果对象是Message<?>,则不会保留入站标头。

更多信息,请参见Javadoc

CodecMessageConverter

某些端点(例如 TCP 和 Redis)没有消息头的概念。它们支持使用MessageConverter,而CodecMessageConverter可用于将消息转换为byte[]或从byte[]转换消息以进行传输。

更多信息,请参见Javadoc

Kryo

目前,这是Codec的唯一实现,它提供了两种Codec

  • PojoCodec:用于转换器。

  • MessageCodec:用于CodecMessageConverter

框架提供了一些自定义序列化器:

  • FileSerializer

  • MessageHeadersSerializer

  • MutableMessageHeadersSerializer

第一个可以通过使用FileKryoRegistrar初始化来与PojoCodec一起使用。第二个和第三个与MessageCodec一起使用,后者使用MessageKryoRegistrar初始化。

自定义 Kryo

默认情况下,Kryo 将未知的 Java 类型委托给其FieldSerializer。Kryo 还为每种原始类型以及StringCollectionMap注册默认序列化器。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接口公开了KryoInputOutput,它们提供了对包含哪些字段和其他内部设置的完全控制,如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 注册类,这可能会使该技术在某些情况下无用。