在Spring Integration中使用JSON转换器

时间:2019-05-16 13:38:17

标签: spring spring-integration

在我能找到的任何示例中,我都有一个似乎未解决的问题。

我的应用程序读取JSON消息的ActiveMQ主题。它将基于此数据构建一个全新的出站REST调用。请注意,这不是“转换”。赋予它“ X”产生“ Y”,即ServiceActivator。

到目前为止,我的流量是

public IntegrationFlow splitInputFlow() {
    return IntegrationFlows.from("inboundJmsChannel")
            .split()
            .log(LoggingHandler.Level.DEBUG)
            .route(Message.class, m -> m.getHeaders().get("x-bn-class").equals("Healthcheck.class") ? "healthcheckChannel" : "metricChannel")
            .get();
}

public IntegrationFlow healthcheckFlow() {
    return IntegrationFlows.from("healthcheckChannel")
            .log(LoggingHandler.Level.DEBUG)
        .transform(Transformers.fromJson(Healthcheck.class))
        .handle("healthcheckActivator", "process")
        .get();
}

关于如何使用弹簧变压器的例子有很多。我什至考虑过尝试使用MessageConverter。但是我不知道为什么会有帮助,而且这也不是正常的方法。

这里的主要问题是Integration调用healthcheckActivator.process(String payload)。有效负载本身是预期的有效JSON字符串。

令我有些惊讶的是它没有调用healtcheckActivator.process(Messagepayload),但是那没有帮助,所以没什么大不了的。

真正的问题是,为什么不调用healtcheckActivator.process(Healthcheck healthcheck)?

实际上我理解“为什么”。这是因为DSL生成了一个内部通道来将各个步骤捆绑在一起,据我所知,通道上的任何内容都是spring.messaging.Message。

一旦进入SA,我就可以轻松实例化Healthcheck对象。但这留下了一个棘手的问题:整个转换步骤可能有什么好处?如果它总是将对象“序列化”回一条消息中,那有什么意义。

就像我说的那样,我认为我在这里缺少一些基本的东西。

编辑 我的新想法(可能也是最后一个想法)可能是我发布的错误。

要发布它,我正在使用

jmsTemplate.convertAndSend(topicName, healthcheck, messagePostProcessor -> {
            messagePostProcessor.setJMSType("TextMessage");
            messagePostProcessor.setStringProperty("x-bn-class", "Healthcheck.class");
            messagePostProcessor.setStringProperty("x-bn-service-name", restEndpoint.getServiceName());
            messagePostProcessor.setStringProperty("x-bn-service-endpoint-name", restEndpoint.getEndpointName());
            messagePostProcessor.setLongProperty("x-bn-heathcheck-timestamp", queryDate);
            messagePostProcessor.setStringProperty("x-bn-healthcheck-status", subsystemStatus.getStatus(subsystemStatus));
            messagePostProcessor.setIntProperty("httpStatus", httpStatus.value());
            return messagePostProcessor;
        });

SI处理(字符串有效负载)方法的结果是:

LoggingHandler - GenericMessage [payload={"healthcheckType":"LOCAL","outcome":"PASS","dependencyType":"DB","endpoint":"NODE TABLE","description":"Read from DB","durationSecs":0.025}, headers={x-bn-service-name=TG10-CS2, x-bn-service-endpoint-name=TG Q10-CS2 Ready Check, jms_destination=topic://HEALTH_MONITOR, _type=com.healthcheck.response.Healthcheck, x-bn-heathcheck-timestamp=1558356538000, priority=4, jms_timestamp=1558356544244, x-bn-healthcheck-status=SEV0, jms_redelivered=false, x-bn-class=Healthcheck.class, httpStatus=200, jms_type=TextMessage, id=b29ffea7-7128-c543-9a14-8bab450f0ac6, jms_messageId=ID:39479-1558356520091-1:2:1:1:1, timestamp=1558356544409}]

我之前在jms_destination标头中没有注意到_type参数。但是在我开始解决这个问题之前(因为它没有用),这是其他团队提供的正确的类名。

我尚未实现JMS消息转换器。但是提供的SimpleMessageConverter似乎完全可以完成我想要的操作。

2 个答案:

答案 0 :(得分:1)

嗯,Spring Integration是一个 Messaging 框架。它通过之间的通道将消息从端点传输到端点。这已经是目标端点负责以正确方式处理消耗的消息的职责。该框架不关心payload。它实际上是目标应用程序的业务部分。这样,我们就可以使框架组件尽可能通用,从而为最终用户留出目标业务类型的空间。

无论如何,框架提供了一些与有效载荷进行交互的机制。我们称其为 POJO方法调用。因此,您需要为某些业务提供任意合同,但是要遵循一些Spring Integration规则:https://docs.spring.io/spring-integration/docs/current/reference/html/#service-activator

因此,根据您的描述,它对healtcheckActivator.process(Healthcheck healthcheck)不起作用确实令人惊讶。您的transform(Transformers.fromJson(Healthcheck.class))实际上应该产生一个Message对象作为负载的Healthcheck。该框架会查询方法签名,并尝试将有效负载和/或标头映射到方法调用参数,并将整个消息作为用于将数据委派给方法调用的容器。

从这里开始,很高兴看到您的healtcheckActivator.process()方法确定为什么transform(Transformers.fromJson(Healthcheck.class))结果炮被映射到该方法参数。

答案 1 :(得分:1)

您的理解是正确的;对我来说效果很好,所以还有其他事情发生...

@SpringBootApplication
public class So56169938Application {

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

    @Bean
    public IntegrationFlow flow() {
        return IntegrationFlows.from(() -> "{\"foo\":\"bar\"}", e -> e.poller(Pollers.fixedDelay(5000)))
            .transform(Transformers.fromJson(Foo.class))
            .handle("myBean", "method")
            .get();
    }

    @Bean
    public MyBean myBean() {
        return new MyBean();
    }

    public static class MyBean {

        public void method(Foo foo) {
            System.out.println(foo);
        }

    }

    public static class Foo {

        private String foo;

        String getFoo() {
            return this.foo;
        }

        void setFoo(String foo) {
            this.foo = foo;
        }

        @Override
        public String toString() {
            return "Foo [foo=" + this.foo + "]";
        }

    }

}

Foo [foo=bar]
Foo [foo=bar]
Foo [foo=bar]
Foo [foo=bar]
Foo [foo=bar]
Foo [foo=bar]