Spring Integration - Transformations



Reference

Transformer 用來轉換收進來的訊息
Example 把 Map 或 String 改為 TextMessage. Mapper 掛上 @Transformer 就是註冊 Transformer, 根據 parameter type 可以自動判斷哪個 transformer method 要被呼叫
// Mapper
@Component
public class Mapper {

    @Transformer
    public TextMessage map(Map<String, String> message) {
        System.out.println("transform from " + message + " to TextMessage");
        return new TextMessage(message.get("text"));
    }

    @Transformer
    public TextMessage map(String message) {
        System.out.println("transform from string to TextMessage");
        return new TextMessage(message);
    }

}

// TextMessage
public class TextMessage {

    private final String text;

    public TextMessage(String text) {
        this.text = text;
    }

    @Override
    public String toString() {
        return text;
    }
}

// TransformerMain.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:int="http://www.springframework.org/schema/integration"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/integration
        http://www.springframework.org/schema/integration/spring-integration-5.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    <context:component-scan base-package="examples.transformer"/>
    <int:transformer input-channel="input"
                     output-channel="output"
                     ref="mapper"/>
    <int:channel id="input"/>
    <int:channel id="output">
        <int:queue capacity="10"/>
    </int:channel>
</beans>

// TransformerMain.java
public class TransformerMain {

    public static void main(String[] params) {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:TransformerMain.xml");
        MessageChannel input = ctx.getBean("input", MessageChannel.class);
        PollableChannel output = ctx.getBean("output", PollableChannel.class);
        Map<String,String> message = new HashMap<>();
        message.put("text", "here");
        input.send(MessageBuilder.withPayload(message).build());
        System.out.println(output.receive().getPayload());


        input.send(MessageBuilder.withPayload("fromString").build());
        System.out.println(output.receive().getPayload());
    }

}


Object-to-string transformer
Example 不用設定 mapper 就會呼叫 toString 轉換
// ObjectToStringTransformer.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:int="http://www.springframework.org/schema/integration"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/integration
        http://www.springframework.org/schema/integration/spring-integration-5.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    <context:component-scan base-package="examples.transformer"/>
    <int:object-to-string-transformer input-channel="input" output-channel="output" />
    <int:channel id="input"/>
    <int:channel id="output">
        <int:queue capacity="10"/>
    </int:channel>
</beans>

public class ObjectToStringTransformerMain {

    public static void main(String[] params) {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:ObjectToStringTransformerMain.xml");
        MessageChannel input = ctx.getBean("input", MessageChannel.class);
        PollableChannel output = ctx.getBean("output", PollableChannel.class);
        Map<String,String> message = new HashMap<>();
        message.put("text", "here");
        input.send(MessageBuilder.withPayload(message).build());
        System.out.println(output.receive().getPayload());


        input.send(MessageBuilder.withPayload("fromString").build());
        System.out.println(output.receive().getPayload());
    }

}

Payload-serializer-transformer 對 payload 直接做 serialize/deserialize
Example localId in TextMessage 是 transient, 所以不會被 serialize/deserialize
// XML
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:int="http://www.springframework.org/schema/integration"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/integration
        http://www.springframework.org/schema/integration/spring-integration-5.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    <context:component-scan base-package="examples.transformer"/>
    <int:payload-serializing-transformer input-channel="input" output-channel="byte-array" />
    <int:payload-deserializing-transformer input-channel="byte-array" output-channel="output" />
    <int:channel id="byte-array" />
    <int:channel id="input"/>
    <int:channel id="output">
        <int:queue capacity="10"/>
    </int:channel>
</beans>


public class TextMessage implements Serializable {

    private final String text;
    private final transient String localId;

    public TextMessage(String text) {
        this(text, UUID.randomUUID().toString());
    }

    public TextMessage(String text, String localId) {
        this.text = text;
        this.localId = localId;
    }

    @Override
    public String toString() {
        return localId + ":" + text;
    }
}

public class PayloadSerializingTransformerMain {

    public static void main(String[] params) {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:PayloadSerializingTransformerMain.xml");
        MessageChannel input = ctx.getBean("input", MessageChannel.class);
        PollableChannel output = ctx.getBean("output", PollableChannel.class);
        TextMessage message = new TextMessage("testa", "1");

        input.send(MessageBuilder.withPayload(message).build());
        System.out.println(output.receive().getPayload()); // localId will become null
    }

}



Map-to-object transformer 替 payload 做 marshal/unmarshal to map
Example 這裡要注意的是 訊息必須有空的建構子與 setter/getter, 不然會失敗
// XML
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:int="http://www.springframework.org/schema/integration"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/integration
        http://www.springframework.org/schema/integration/spring-integration-5.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    <context:component-scan base-package="examples.transformer"/>
    <int:object-to-map-transformer input-channel="input" output-channel="map" />
    <int:map-to-object-transformer input-channel="map" output-channel="output" type="examples.transformer.TextMessageEmptyConstructor" />
    <int:channel id="map" />
    <int:channel id="input"/>
    <int:channel id="output">
        <int:queue capacity="10"/>
    </int:channel>
</beans>

// Payload class
public class TextMessageEmptyConstructor {

    private String text;

    public TextMessageEmptyConstructor() {}
    public TextMessageEmptyConstructor(String text) {
        this.text = text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public String getText() {
        return text;
    }

    @Override
    public String toString() {
        return text;
    }
}

// Transformer
public class MapToObjectTransformerMain {

    public static void main(String[] params) {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:MapToObjectTransformerMain.xml");
        MessageChannel input = ctx.getBean("input", MessageChannel.class);
        PollableChannel output = ctx.getBean("output", PollableChannel.class);

        TextMessageEmptyConstructor message = new TextMessageEmptyConstructor("testa");

        input.send(MessageBuilder.withPayload(message).build());
        System.out.println(output.receive().getPayload()); // localId will become null
    }

}


Object-to-json transformer payload 會轉成 json 再轉回 payload 物件
Example
// XML
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:int="http://www.springframework.org/schema/integration"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/integration
        http://www.springframework.org/schema/integration/spring-integration-5.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    <context:component-scan base-package="examples.transformer"/>
    <int:object-to-json-transformer input-channel="input" output-channel="json" />
    <int:json-to-object-transformer input-channel="json" output-channel="output" type="examples.transformer.TextMessageEmptyConstructor" />

    <int:channel id="json" />
    <int:channel id="input"/>
    <int:channel id="output">
        <int:queue capacity="10"/>
    </int:channel>
</beans>

// transformer
public class ObjectToJsonTransformerMain {

    public static void main(String[] params) {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:ObjectToJsonTransformerMain.xml");
        MessageChannel input = ctx.getBean("input", MessageChannel.class);
        PollableChannel output = ctx.getBean("output", PollableChannel.class);

        TextMessageEmptyConstructor message = new TextMessageEmptyConstructor("test-object-to-json");

        input.send(MessageBuilder.withPayload(message).build());
        System.out.println(output.receive().getPayload());
    }

}



沒有留言:

張貼留言

別名演算法 Alias Method

 題目 每個伺服器支援不同的 TPM (transaction per minute) 當 request 來的時候, 系統需要馬上根據 TPM 的能力隨機找到一個適合的 server. 雖然稱為 "隨機", 但還是需要有 TPM 作為權重. 解法 別名演算法...