这是shopping cart sample的延续,我们有一个外部API,允许从购物车结帐。回顾一下,我们有一个流程,我们创建一个空的购物,添加行项目,最后结帐。上面的所有操作都是通过HTTP调用外部服务来实现的。我们想要同时添加订单项(作为添加订单项的一部分)调用。我们当前的配置如下所示:
@Bean
public IntegrationFlow fullCheckoutFlow() {
return f -> f.channel("inputChannel")
.transform(fromJson(ShoppingCart.class))
.enrich(e -> e.requestChannel(SHOPPING_CART_CHANNEL))
.split(ShoppingCart.class, ShoppingCart::getLineItems)
.enrich(e -> e.requestChannel(ADD_LINE_ITEM_CHANNEL))
.aggregate(aggregator -> aggregator
.outputProcessor(g -> g.getMessages()
.stream()
.map(m -> (LineItem) m.getPayload())
.map(LineItem::getName)
.collect(joining(", "))))
.enrich(e -> e.requestChannel(CHECKOUT_CHANNEL))
.<String>handle((p, h) -> Message.called("We have " + p + " line items!!"));
}
@Bean
public IntegrationFlow addLineItem(Executor executor) {
return f -> f.channel(MessageChannels.executor(ADD_LINE_ITEM_CHANNEL, executor).get())
.handle(outboundGateway("http://localhost:8080/api/add-line-item", restTemplate())
.httpMethod(POST)
.expectedResponseType(String.class));
}
@Bean
public Executor executor(Tracer tracer, TraceKeys traceKeys, SpanNamer spanNamer) {
return new TraceableExecutorService(newFixedThreadPool(10), tracer, traceKeys, spanNamer);
}
@Bean
public IntegrationFlow fullCheckoutFlow() {
return f -> f.channel("inputChannel")
.transform(fromJson(ShoppingCart.class))
.enrich(e -> e.requestChannel(SHOPPING_CART_CHANNEL))
.split(ShoppingCart.class, ShoppingCart::getLineItems)
.enrich(e -> e.requestChannel(ADD_LINE_ITEM_CHANNEL))
.aggregate(aggregator -> aggregator
.outputProcessor(g -> g.getMessages()
.stream()
.map(m -> (LineItem) m.getPayload())
.map(LineItem::getName)
.collect(joining(", "))))
.enrich(e -> e.requestChannel(CHECKOUT_CHANNEL))
.<String>handle((p, h) -> Message.called("We have " + p + " line items!!"));
}
@Bean
public IntegrationFlow addLineItem(Executor executor) {
return f -> f.channel(MessageChannels.executor(ADD_LINE_ITEM_CHANNEL, executor).get())
.handle(outboundGateway("http://localhost:8080/api/add-line-item", restTemplate())
.httpMethod(POST)
.expectedResponseType(String.class));
}
@Bean
public Executor executor(Tracer tracer, TraceKeys traceKeys, SpanNamer spanNamer) {
return new TraceableExecutorService(newFixedThreadPool(10), tracer, traceKeys, spanNamer);
}
要并行添加订单项,我们正在使用执行程序渠道。但是,在zipkin中看到它们似乎仍然是按顺序处理的:
我们做错了什么?整个项目的来源位于github以供参考。
谢谢!
答案 0 :(得分:1)
首先,Spring Integration的主要功能是MessageChannel
,但我仍然不清楚为什么人们在端点定义之间缺少.channel()
运算符。
我的意思是,对于你的情况,它必须是:
.split(ShoppingCart.class, ShoppingCart::getLineItems)
.channel(c -> c.executor(executor()))
.enrich(e -> e.requestChannel(ADD_LINE_ITEM_CHANNEL))
现在关于你的特殊问题。
看,ContentEnricher
(.enrich()
)是请求 - 回复组件:http://docs.spring.io/spring-integration/reference/html/messaging-transformation-chapter.html#payload-enricher。
因此,它向requestChannel
发送请求并等待回复。它独立于requestChannel
类型完成。
我是原始Java,我们可以使用此代码片段演示此类行为:
for (Object item: items) {
Data data = sendAndReceive(item);
}
您应该看到ADD_LINE_ITEM_CHANNEL
ExecutorChannel
作为.split()
的价值不大,因为无论如何我们都会在循环中被阻止。
DirectChannel
执行完全相似的循环,但由于默认情况下它与.enrich()
一致,因此迭代在同一个线程中完成。因此,每个下一个项目都会等待前一个项目的回复。
这就是为什么你绝对应该在.split()
之后完全与function getPopularMovies()
{
var deferred = $q.defer();
var popularmoviesurl = "https://api.themoviedb.org/3/movie/popular?api_key=adf3d78d5c0f38313a68de730f02063a";
$http({method:'GET',url:popularmoviesurl}).
success(function (data, status, headers, config) {
if (status == 200) {
deferred.resolve(data.results);
} else {
console.error('Error happened while getting the movie list.')
deferred.reject();
}
}).error(function (data, status, headers, config) {
deferred.reject();
console.error('Error happened while getting the movie list.')
});
return deferred.promise;
}
的输入并行。