我想了解PublishSubscribeChannel的工作原理,所以我实现了一个小例子:
@Bean
public MessageSource<?> integerMessageSource() {
MethodInvokingMessageSource source = new MethodInvokingMessageSource();
source.setObject(new AtomicInteger());
source.setMethodName("getAndIncrement");
return source;
}
@Bean
public IntegrationFlow mainFlow() {
// @formatter:off
return IntegrationFlows
.from(integerMessageSource(), c -> c.poller(Pollers.fixedRate(1000)))
.publishSubscribeChannel(pubSub -> pubSub
.subscribe(flow -> flow
.handle(message -> LOG.info("Handling message, step 1: {}", message.getPayload())))
.subscribe(flow -> flow
.handle(message -> LOG.info("Handling message, step 2: {}", message.getPayload())))
.subscribe(flow -> flow
.transform(source -> MessageBuilder.withPayload("Error").build())
.handle(message -> {
LOG.info("Error");
}))
.subscribe(flow -> flow
.handle(message -> LOG.info("Handling message, step 4: {}", message.getPayload())))
)
.get();
// @formatter:on
}
我预计我会看到输出:
Handling message, step 1...
Handling message, step 2...
Error
Handling message, step 4...
但是始终首先处理第三个子流(带有“错误”输出)。当我尝试为步骤1,2和4定义一个订单时,我得到以下控制台输出(警告):
o.s.integration.dsl.GenericEndpointSpec : 'order' can be applied only for AbstractMessageHandler
我原本预计会按订阅顺序调用订阅者,但情况似乎并非如此。
我正在使用Spring Boot 1.5.4和Spring Integration 4.3.10。
答案 0 :(得分:2)
问题是lambda处理程序不是Ordered
- 发布/订阅通道的一般合同是首先(按顺序)调用Ordered
订阅者,然后是无序订阅者。
由于lambdas不能实现多个接口,我不确定我们能做什么。
作为一种解决方法,你可以做类似的事情......
@Bean
public IntegrationFlow mainFlow() {
// @formatter:off
return IntegrationFlows
.from(integerMessageSource(), c -> c.poller(Pollers.fixedRate(1000)))
.publishSubscribeChannel(pubSub -> pubSub
.subscribe(flow -> flow
.handle(handler("Handling message, step 1: {}")))
.subscribe(flow -> flow
.handle(handler("Handling message, step 2: {}")))
.subscribe(flow -> flow
.transform(message -> "Error")
.handle(message -> {
LOG.info("Error");
}))
.subscribe(flow -> flow
.handle(handler("Handling message, step 4: {}")))
)
.get();
// @formatter:on
}
private MessageHandler handler(String format) {
return new AbstractMessageHandler() {
@Override
protected void handleMessageInternal(Message<?> message) throws Exception {
LOG.info(format, message.getPayload());
}
};
}
所有订阅者都是Ordered
。
修改强>
这是一个稍微简单的解决方法 - 使用桥而不是lambda启动子流,因此所有子流第一个组件都实现Ordered
...
@Bean
public IntegrationFlow mainFlow() {
// @formatter:off
return IntegrationFlows
.from(integerMessageSource(), c -> c.poller(Pollers.fixedRate(1000)))
.publishSubscribeChannel(pubSub -> pubSub
.subscribe(flow -> flow
.bridge(e -> e.id("s1"))
.handle(message -> LOG.info("Handling message, step 1: {}", message.getPayload())))
.subscribe(flow -> flow
.bridge(e -> e.id("s2"))
.handle(message -> LOG.info("Handling message, step 2: {}", message.getPayload())))
.subscribe(flow -> flow
.transform(source -> MessageBuilder.withPayload("Error").build())
.handle(message -> {
LOG.info("Error");
}))
.subscribe(flow -> flow
.bridge(e -> e.id("s4"))
.handle(message -> LOG.info("Handling message, step 4: {}", message.getPayload())))
)
.get();
// @formatter:on
}