編解碼器

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[] 或從 byte[] 轉換訊息以進行傳輸。

有關更多資訊,請參閱Javadoc

Kryo

目前,這是 Codec 的唯一實現,它提供了三種 Codec

  • PojoCodec:用於轉換器中

  • MessageCodec:用於 CodecMessageConverter

  • CompositeCodec:用於轉換器中

該框架提供了幾個自定義序列化器

  • FileSerializer

  • MessageHeadersSerializer

  • MutableMessageHeadersSerializer

第一個可以透過使用 FileKryoRegistrar 初始化來與 PojoCodec 一起使用。第二個和第三個與 MessageCodec 一起使用,該 MessageCodec 使用 MessageKryoRegistrar 初始化。

CompositeCodec

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 選項。如果 failOnTiefalse,它將返回任何一個匹配的編解碼器。如果 failOnTietrue 並且多個編解碼器匹配,它將丟擲 IllegalStateExceptionCompositeCodecfailOnTie 設定為 true,因此如果多個編解碼器匹配,則會丟擲 IllegalStateException

自定義 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());
    }
}

Kryo 文件中所述,Serializer 介面公開了 KryoInputOutput,它們提供了對要包含的欄位和其他內部設定的完全控制。

註冊自定義序列化器時,您需要一個註冊 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 註冊類,這可能會使該技術在某些情況下無用。

© . This site is unofficial and not affiliated with VMware.