问题
I want to process a list of items in parallel by splitting them, routing each item to their appropriate gateway and aggregating the results. However, my application does not start, I get the following error:
BeanCreationException: The 'currentComponent' ... is a one-way 'MessageHandler'
and it isn't appropriate to configure 'outputChannel'.
This is the end of the integration flow.
This is a sample flow definition which illustrates the behaviour:
@Bean
public IntegrationFlow parallelSplitRouteAggregateFlow() {
return IntegrationFlows
.from(Http.inboundGateway("/trigger"))
.handle(message -> Arrays.asList(1, 2, 3))
.split()
.channel(MessageChannels.executor(Executors.newCachedThreadPool()))
.<Integer, Boolean>route(o -> o % 2 == 0, m -> m
.subFlowMapping(true, oddFlow())
.subFlowMapping(false, evenFlow()))
.aggregate()
.get();
}
@Bean
public IntegrationFlow oddFlow() {
return flow -> flow.<Integer>handle((payload, headers) -> "odd");
}
@Bean
public IntegrationFlow evenFlow() {
return flow -> flow.<Integer>handle((payload, headers) -> "even");
}
I have seen Error 'is a one-way 'MessageHandler' for spring-integration aggregator DSL, but the solution there does not apply here, I am not logging in a handle() method. I also tried to add .defaultOutputToParentFlow() to the mappingDefinition because the cafe example uses it, but that makes no difference either.
I should mention that this is spring-integration 5.0.4 with spring-boot 2.0.1 release.
回答1:
You problem is here:
.handle(message -> Arrays.asList(1, 2, 3))
if you would use an inline implementation, it would look like:
.handle(new MessageHandler() {
@Override
public void handleMessage(Message<?> message) throws MessagingException {
Arrays.asList(1, 2, 3);
}
})
Pay attention to the void
return type. Since there is nothing to return, therefore there is nothing to send downstream - is a one-way 'MessageHandler'
.
To fix your problem you need to do this:
.handle((p, h) -> Arrays.asList(1, 2, 3))
which is equivalent to this:
.handle(new GenericHandler<Object>() {
@Override
public Object handle(Object p, Map<String, Object> h) {
return Arrays.asList(1, 2, 3);
}
})
Actually my IDEA say me for your variant like:
That gives me some hint that I'm doing something wrong.
UPDATE
The working code:
@Bean
public IntegrationFlow parallelSplitRouteAggregateFlow() {
return IntegrationFlows
.from(Http.inboundGateway("/trigger"))
.handle((p, h) -> Arrays.asList(1, 2, 3))
.split()
.channel(MessageChannels.executor(Executors.newCachedThreadPool()))
.<Integer, Boolean>route(o -> o % 2 == 0, m -> m
.subFlowMapping(true, sf -> sf.gateway(oddFlow()))
.subFlowMapping(false, sf -> sf.gateway(evenFlow())))
.aggregate()
.get();
}
@Bean
public IntegrationFlow oddFlow() {
return flow -> flow.<Integer>handle((payload, headers) -> "odd");
}
@Bean
public IntegrationFlow evenFlow() {
return flow -> flow.<Integer>handle((payload, headers) -> "even");
}
回答2:
@Bean
public IntegrationFlow parallelSplitRouteAggregateFlow() {
return IntegrationFlows
.from(Http.inboundGateway("/trigger"))
.handle((p, h) -> Arrays.asList(1, 2, 3))
.split()
.channel(MessageChannels.executor(Executors.newCachedThreadPool()))
.<Integer, Boolean>route(o -> o % 2 == 0, m -> m
.subFlowMapping(true, oddFlow())
.subFlowMapping(false, evenFlow()))
.get();
}
@Bean
public IntegrationFlow oddFlow() {
return flow -> flow.<Integer>handle((payload, headers) -> "odd")
.channel("agg.input");
}
@Bean
public IntegrationFlow evenFlow() {
return flow -> flow.<Integer>handle((payload, headers) -> "even")
.channel("agg.input");
}
@Bean
public IntegrationFlow agg() {
return f -> f.aggregate();
}
回答3:
If what you need is to "distribute" messages over several "workers", and have the messages back at a join point, there's the method .scatterGather(...)
. Deemingly, it wraps up the .route(...)
functionality in a way more suitable to be used within the IntegrationFlow's domain.
It is showed in the following example:
@Bean
public IntegrationFlow evenOddFlows() {
return IntegrationFlows.from(Http.inboundGateway("/trigger"))
.handle((payload,headers)->Arrays.asList(1,2,3))
.split()
.scatterGather(r->r.applySequence(true)
.recipientFlow(m->(int)m.getPayload()%2==0, evenFlow-> evenFlow.log(m->"Even flow with payload: "+m.getPayload()).<Integer,Integer>transform(h-> h+50)
.handle((payload,headers)->(int)payload+50).log(m->"At Even flow end with payload: "+m.getPayload())
.handle((payload,headers)->payload) /* This .handle(...) doesn't do a real job.
* Instead, it is to patch something that at least I regard as a bug.
* Having not the .handle(...) would leave the .log(...) at the end of the flow.
* After crossing a .log(...) if right at the flow's end, the response message doesn't arrive back the parent flow (hence my aprising there is a bug).
* With the "appended" .handle(...) afterwards, avoid the .log(...) being the last one in the flow, as well as tests show the message is sent away where the parent flow receives it.
*/
)
.recipientFlow(m->(int)m.getPayload()%2!=0, oddFlow-> oddFlow.log(m->"Odd flow with payload: "+m.getPayload()).<Integer,Integer>transform(h-> h+10)
.handle((payload,headers)->(int)payload+10).log(m->"At Odd flow end with payload: "+m.getPayload())
.handle((payload,headers)->payload) // This .handle(...) I needed as a patch because otherwise the .log(...) being the last one in the subflow swallowed the message
)
)
.aggregate()
.get()
;
}
curl -i -H "Content-type: application/json" http://localhost:8080/trigger
Curl outputs:
[[21],[102],[23]]
Logs:
2019-05-17 16:19:11.061 INFO 10148 --- [nio-8080-exec-1] o.s.integration.handler.LoggingHandler : Odd flow with payload: 1
2019-05-17 16:19:11.061 INFO 10148 --- [nio-8080-exec-1] o.s.integration.handler.LoggingHandler : At Odd flow end with payload: 21
2019-05-17 16:19:11.061 INFO 10148 --- [nio-8080-exec-1] o.s.integration.handler.LoggingHandler : Even flow with payload: 2
2019-05-17 16:19:11.061 INFO 10148 --- [nio-8080-exec-1] o.s.integration.handler.LoggingHandler : At Even flow end with payload: 102
2019-05-17 16:19:11.061 INFO 10148 --- [nio-8080-exec-1] o.s.integration.handler.LoggingHandler : Odd flow with payload: 3
2019-05-17 16:19:11.061 INFO 10148 --- [nio-8080-exec-1] o.s.integration.handler.LoggingHandler : At Odd flow end with payload: 23
来源:https://stackoverflow.com/questions/50121384/spring-integration-parallel-split-route-aggregate-flow-fails-due-to-one-way-mess