簡體   English   中英

使用通道和網關的Spring Integration DSL中的Echo套接字服務

[英]Echo socket service in Spring Integration DSL using Channels and Gateways

這是我的問題的變體, 如何在Spring Integration DSL中實現簡單的回顯套接字服務 介紹了一個好的工作解決方案,但我想探索替代方案。 我特別對基於客戶端和服務器實現中顯式使用入站和出站通道的解決方案感興趣。 那可能嗎?

到目前為止,我能夠提出:

HeartbeatClientConfig

...
@Bean
public IntegrationFlow heartbeatClientFlow(
        TcpNetClientConnectionFactory clientConnectionFactory,
        MessageChannel outboundChannel,
        PollableChannel inboundChannel) {
    return IntegrationFlows
            .from(outboundChannel)
            .handle(Tcp.outboundGateway(clientConnectionFactory))
            .channel(inboundChannel)
            .get();
}
...

HeartbeatClient

public HeartbeatClient(MessageChannel outboudChannel, PollableChannel inboundChannel) {
    this.inboundChannel = inboundChannel;
    this.outboudChannel = outboudChannel;
}
...
void run() {
    // ..in scheduled intervals in loop 
    outboudChannel.send(new GenericMessage<String>("status"));
    Message<?> message = inboundChannel.receive(1000);
}

客戶端部分似乎工作正常。 問題出在服務器端。

HeartbeatServer

public HeartbeatServer(PollableChannel inboundChannel, MessageChannel outboudChannel) {
    this.inboundChannel = inboundChannel;
    this.outboudChannel = outboudChannel;
}
...
void run() {
    // ..in some kind of loop
    Message<?> message = inboundChannel.receive(1000); // presumably a blocking call
    ...
    outboudChannel.send(new GenericMessage<>("OK"));
    ...
}

HeartbeatServerConfig
這是最棘手的部分,我確定我錯了。 我只是不知道該怎么辦。 在這里,我天真地使用了客戶端實現中似乎可行的逆方法。 在Flow定義中切換入站和出站通道的意義上相反。

...
@Bean
public IntegrationFlow heartbeatServerFlow(
        MessageChannel outboundChannel,
        PollableChannel inboundChannel) {
    return IntegrationFlows
            .from(inboundChannel)
            .handle(Tcp.inboundGateway(Tcp.netServer(7777)))
            .channel(outboundChannel)
            .get();
}
...

服務器無法正常工作,引發關於Found ambiguous parameter type [class java.lang.Boolean] for method match ...神秘異常Found ambiguous parameter type [class java.lang.Boolean] for method match ...隨后是一長串的Spring和Spring Integration方法。

完整的源代碼可以在這里找到

您無法使用通道啟動服務器端流。

該流程從網關開始; 它處理所有套接字通信。 當收到消息時,它將其發送到頻道。

你可以做...

@Bean
public IntegrationFlow server(PollableChannel requests, MessageChannel replies) {
    return IntegrationFlows.from(Tcp.inboundGateway(Tcp.netServer(1234))
                .replyChannel(replies))
            .transform(Transformers.objectToString())
            .channel(requests)
            .get();
}

但是我想問一下為什么要這么做,因為現在您必須管理自己的線程才能從請求通道接收並寫入回復通道。 為了replyChannel起作用, 必須將請求消息中的replyChannel標頭復制到回復消息中 實際上,您實際上並不需要回復渠道; 您可以直接將回復發送到replyChannel標頭(這是內部發生的情況,我們將回復通道橋接到標頭通道)。

在網關的線程上處理請求要簡單得多。

只是為了補充加里(Gary)的完美答案,如果有人感興趣,這是完整的代碼。

我必須明確指定TcpNetServerConnectionFactory ,以將ByteArrayLengthHeaderSerializer設置為序列化器/反序列化器。 沒有它就無法工作。

HeartbeatServerConfig的 完整代碼

@Bean
public TcpNetServerConnectionFactory connectionFactory() {
    TcpNetServerConnectionFactory connectionFactory = new TcpNetServerConnectionFactory(7777);
    connectionFactory.setSerializer(new ByteArrayLengthHeaderSerializer());
    connectionFactory.setDeserializer(new ByteArrayLengthHeaderSerializer());
    return connectionFactory;
}

@Bean
public IntegrationFlow heartbeatServerFlow(
        TcpNetServerConnectionFactory connectionFactory,
        PollableChannel inboundChannel, 
        MessageChannel outboundChannel) {
    return IntegrationFlows.from(Tcp.inboundGateway(connectionFactory)
            .replyChannel(outboundChannel))
            .channel(inboundChannel)
            .get();
}

HeartbeatServer 完整代碼

public void start() {
    Executors.newSingleThreadExecutor().execute(() -> {
        while (true) {
            try {
                Message<?> request = inboundChannel.receive();
                if (request == null) {
                    log.error("Heartbeat timeouted");
                } else {
                    MessageChannel outboudChannel = (MessageChannel)request.getHeaders().getReplyChannel();
                    String requestPayload = new String((byte[]) request.getPayload());
                    if (requestPayload.equals("status")) {
                        log.info("Heartbeat received");
                        outboudChannel.send(new GenericMessage<>("OK"));
                    } else {
                        log.error("Unexpected message content from client: " + requestPayload);
                    }
                }
            } catch (Exception e) {
                log.error(e);
            }
        }
    });
}

當然,關鍵的一點是從請求消息本身獲取出站通道,如下所示: MessageChannel outboudChannel = (MessageChannel)request.getHeaders().getReplyChannel()

完整的代碼可以在這里找到。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM