Codec

Spring Integration 的版本 4.2 引入了 Codec 抽象。编解码器对对象进行编码和解码,使其可以进入和离开 byte[] 。它们为 Java 序列化提供了一种替代方式。一个优点是,通常不需要对象实现 Serializable 。我们提供了一个实现,它使用 Kryo 进行序列化,但是你可以在任何以下组件中提供自己的实现:

Version 4.2 of Spring Integration introduced the Codec abstraction. Codecs encode and decode objects to and from byte[]. They offer an alternative to Java serialization. One advantage is that, typically, objects need not implement Serializable. We provide one implementation that uses Kryo for serialization, but you can provide your own implementation for use in any of the following components:

  • EncodingPayloadTransformer

  • DecodingTransformer

  • CodecMessageConverter

EncodingPayloadTransformer

此变换器通过使用编解码器将有效负载编码到 byte[] 。它不影响邮件标头。

This transformer encodes the payload to a byte[] by using the codec. It does not affect message headers.

有关更多信息,请参见 Javadoc

See the Javadoc for more information.

DecodingTransformer

此变换器通过使用编解码器解码 byte[] 。它需要通过 Class 进行配置,目标对象应解码到配置(或者解析为 Class 的表达式)。如果结果对象是 Message<?> ,则不保留入站标头。

This transformer decodes a byte[] by using the codec. It needs to be configured with the Class to which the object should be decoded (or an expression that resolves to a Class). If the resulting object is a Message<?>, inbound headers are not retained.

有关更多信息,请参见 Javadoc

See the Javadoc for more information.

CodecMessageConverter

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

Certain endpoints (such as TCP and Redis) have no concept of message headers. They support the use of a MessageConverter, and the CodecMessageConverter can be used to convert a message to or from a byte[] for transmission.

有关详细信息,请参见 Javadoc

See the Javadoc for more information.

Kryo

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

Currently, this is the only implementation of Codec, and it provides two kinds of Codec:

  • PojoCodec: Used in the transformers

  • MessageCodec: Used in the CodecMessageConverter

该框架提供了几个自定义序列化器:

The framework provides several custom serializers:

  • FileSerializer

  • MessageHeadersSerializer

  • MutableMessageHeadersSerializer

第一个可与 PojoCodec 一起使用,方法是用 FileKryoRegistrar 对其进行初始化。第二个和第三个与 MessageCodec 一起使用,后者是用 MessageKryoRegistrar 初始化的。

The first can be used with the PojoCodec by initializing it with the FileKryoRegistrar. The second and third are used with the MessageCodec, which is initialized with the MessageKryoRegistrar.

Customizing Kryo

默认情况下,Kryo 将未知的 Java 类型委托给其 FieldSerializer。Kryo 还为每个基本类型注册默认序列化器,以及 StringCollectionMapFieldSerializer 使用反射来导航对象图。一种更有效的方法是实现一个自定义序列化器,该序列化器知道对象的结构,并且可以直接序列化选定的原始字段。以下示例展示了一个这样的序列化器:

By default, Kryo delegates unknown Java types to its FieldSerializer. Kryo also registers default serializers for each primitive type, along with String, Collection, and Map. FieldSerializer uses reflection to navigate the object graph. A more efficient approach is to implement a custom serializer that is aware of the object’s structure and can directly serialize selected primitive fields. The following example shows such a serializer:

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 documentation 中所述。

The Serializer interface exposes Kryo, Input, and Output, which provide complete control over which fields are included and other internal settings, as described in the Kryo documentation.

注册自定义序列化器时,需要注册 ID。注册 ID 是任意的。然而,在我们的案例中,ID 必须被明确定义,因为整个分布式应用程序中的每个 Kryo 实例都必须使用相同的 ID。Kryo 推荐使用小的正整数,并保留一些 ID(值 < 10)。Spring Integration 当前默认使用 40、41 和 42(用于前面提到的文件和消息头序列化器)。我们建议您从 60 开始,以允许框架进行扩展。您可以通过配置前面提到的注册器来覆盖这些框架默认值。

When registering your custom serializer, you need a registration ID. The registration IDs are arbitrary. However, in our case, the IDs must be explicitly defined, because each Kryo instance across the distributed application must use the same IDs. Kryo recommends small positive integers and reserves a few ids (value < 10). Spring Integration currently defaults to using 40, 41, and 42 (for the file and message header serializers mentioned earlier). We recommend you start at 60, to allow for expansion in the framework. You can override these framework defaults by configuring the registrars mentioned earlier.

Using a Custom Kryo Serializer

如果您需要自定义序列化,请查看 Kryo文档,因为您需要使用本机 API 来执行自定义。例如,请查看 `org.springframework.integration.codec.kryo.MessageCodec`实现。

If you need custom serialization, see the Kryo documentation, because you need to use the native API to do the customization. For an example, see the org.springframework.integration.codec.kryo.MessageCodec implementation.

Implementing KryoSerializable

如果您有对域对象源代码的 write 访问权限,则可以按 here 中所述实现 KryoSerializable。在这种情况下,类自行提供序列化方法,无需进一步配置。然而,基准显示,这没有显式注册自定义序列化器那么高效。以下示例显示了自定义 Kryo 序列化器:

If you have write access to the domain object source code, you can implement KryoSerializable as described here. In this case, the class provides the serialization methods itself and no further configuration is required. However, benchmarks have shown this is not quite as efficient as registering a custom serializer explicitly. The following example shows a custom Kryo serializer:

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 之外的序列化库。

You can also use this technique to wrap a serialization library other than Kryo.

Using the @DefaultSerializer Annotation

Kryo 还提供了一个 @DefaultSerializer 批注,如 here 中所述。

Kryo also provides a @DefaultSerializer annotation, as described here.

@DefaultSerializer(SomeClassSerializer.class)
public class SomeClass {
       // ...
}

如果您有权“写入”域对象,这可能是指定自定义序列化程序更简单的方法。请注意,这不会使用 ID 注册类,这对于某些情况可能没有帮助。

If you have write access to the domain object, this may be a simpler way to specify a custom serializer. Note that this does not register the class with an ID, which may make the technique unhelpful for certain situations.