如何在Spring Integration DSL Tcp中使用消息头进行路由

时间:2019-03-20 12:34:48

标签: spring-integration spring-integration-dsl spring-integration-ip

我有2个服务器端服务,我想使用消息头将消息路由到它们,其中远程客户端将服务标识放在字段type中。

服务器端配置中的代码段是否正确?它引发强制转换异常,指示route()仅看到有效负载,而看不到消息头。此外,Spring Integration手册中的所有示例仅显示基于有效负载的决策。

@Bean
public IntegrationFlow serverFlow( // common flow for all my services, currently 2
        TcpNetServerConnectionFactory serverConnectionFactory,
        HeartbeatServer heartbeatServer,
        FeedServer feedServer) {
    return IntegrationFlows
            .from(Tcp.inboundGateway(serverConnectionFactory))
            .<Message<?>, String>route((m) -> m.getHeaders().get("type", String.class),
                (routeSpec) -> routeSpec
                .subFlowMapping("hearbeat", subflow -> subflow.handle(heartbeatServer::processRequest))
                .subFlowMapping("feed", subflow -> subflow.handle(feedServer::consumeFeed)))
            .get();
}

客户端配置:

@Bean
public IntegrationFlow heartbeatClientFlow(
        TcpNetClientConnectionFactory clientConnectionFactory,
        HeartbeatClient heartbeatClient) {
    return IntegrationFlows.from(heartbeatClient::send,  e -> e.poller(Pollers.fixedDelay(Duration.ofSeconds(5))))
            .enrichHeaders(c -> c.header("type", "heartbeat"))
            .log()
            .handle(outboundGateway(clientConnectionFactory))
            .handle(heartbeatClient::receive)
            .get();
}

@Bean
public IntegrationFlow feedClientFlow(
        TcpNetClientConnectionFactory clientConnectionFactory) {
    return IntegrationFlows.from(FeedClient.MessageGateway.class)
            .enrichHeaders(c -> c.header("type", "feed"))
            .log()
            .handle(outboundGateway(clientConnectionFactory))
            .get();
}

和往常一样,这里是完整的演示project codeClientConfigServerConfig

1 个答案:

答案 0 :(得分:1)

没有通过原始TCP发送标头的标准方法。您需要以某种方式将它们编码为有效负载(并在服务器端提取它们)。

该框架提供了一种为您执行此操作的机制,但需要额外的配置。

请参见the documentation

特别是...

  

MapJsonSerializer使用Jackson ObjectMapper在Map和JSON之间进行转换。您可以将此序列化程序与MessageConvertingTcpMessageMapperMapMessageConverter结合使用,以传输选定的标头和JSON中的有效载荷。

我将尝试寻找一些时间来创建一个如何使用它的示例。

但是,当然,您可以滚动自己的编码/解码。

编辑

这是使用JSON通过TCP传递消息头的示例配置...

@SpringBootApplication
public class TcpWithHeadersApplication {

    public static void main(String[] args) {
        SpringApplication.run(TcpWithHeadersApplication.class, args);
    }

    // Client side

    public interface TcpExchanger {

        public String exchange(String data, @Header("type") String type);

    }

    @Bean
    public IntegrationFlow client(@Value("${tcp.port:1234}") int port) {
        return IntegrationFlows.from(TcpExchanger.class)
                .handle(Tcp.outboundGateway(Tcp.netClient("localhost", port)
                        .deserializer(jsonMapping())
                        .serializer(jsonMapping())
                        .mapper(mapper())))
                .get();
    }

    // Server side

    @Bean
    public IntegrationFlow server(@Value("${tcp.port:1234}") int port) {
        return IntegrationFlows.from(Tcp.inboundGateway(Tcp.netServer(port)
                        .deserializer(jsonMapping())
                        .serializer(jsonMapping())
                        .mapper(mapper())))
                .log(Level.INFO, "exampleLogger", "'Received type header:' + headers['type']")
                .route("headers['type']", r -> r
                        .subFlowMapping("upper",
                                subFlow -> subFlow.transform(String.class, p -> p.toUpperCase()))
                        .subFlowMapping("lower",
                                subFlow -> subFlow.transform(String.class, p -> p.toLowerCase())))
                .get();
    }

    // Common

    @Bean
    public MessageConvertingTcpMessageMapper mapper() {
        MapMessageConverter converter = new MapMessageConverter();
        converter.setHeaderNames("type");
        return new MessageConvertingTcpMessageMapper(converter);
    }

    @Bean
    public MapJsonSerializer jsonMapping() {
        return new MapJsonSerializer();
    }

    // Console

    @Bean
    @DependsOn("client")
    public ApplicationRunner runner(TcpExchanger exchanger,
            ConfigurableApplicationContext context) {

        return args -> {
            System.out.println("Enter some text; if it starts with a lower case character,\n"
                    + "it will be uppercased by the server; otherwise it will be lowercased;\n"
                    + "enter 'quit' to end");
            Scanner scanner = new Scanner(System.in);
            String request = scanner.nextLine();
            while (!"quit".equals(request.toLowerCase())) {
                if (StringUtils.hasText(request)) {
                    String result = exchanger.exchange(request,
                            Character.isLowerCase(request.charAt(0)) ? "upper" : "lower");
                    System.out.println(result);
                }
                request = scanner.nextLine();
            }
            scanner.close();
            context.close();
        };
    }

}