Как маршрутизировать с использованием заголовков сообщений в Spring Integration DSL Tcp - PullRequest
0 голосов
/ 20 марта 2019

У меня есть 2 службы на стороне сервера, и я хотел бы направить им сообщения с использованием заголовков сообщений, где удаленные клиенты помещают идентификацию службы в поле type.

Это фрагмент кода из конфигурации на стороне сервера,правильный путь?Выдает исключение приведения, указывающее, что route() видит только полезную нагрузку, но не заголовки сообщения.Также весь пример в руководстве по интеграции с Spring показывает только решения, основанные на полезной нагрузке.

@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();
}

И, как обычно, здесь приведен полный демонстрационный код код проекта , ClientConfig и ServerConfig .

1 Ответ

1 голос
/ 20 марта 2019

Не существует стандартного способа отправки заголовков через сырой TCP. Вам нужно как-то кодировать их в полезную нагрузку (и извлекать их на стороне сервера).

Фреймворк предоставляет механизм, который сделает это за вас, но требует дополнительной настройки.

См. документацию .

В частности ...

MapJsonSerializer использует Jackson ObjectMapper для преобразования между картой и JSON. Вы можете использовать этот сериализатор вместе с MessageConvertingTcpMessageMapper и MapMessageConverter для передачи выбранных заголовков и полезной нагрузки в JSON.

Я постараюсь найти время, чтобы создать пример того, как его использовать.

Но, конечно, вы можете свернуть свое собственное кодирование / декодирование.

EDIT

Вот пример конфигурации для использования 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();
        };
    }

}
...