您好我想知道如何在pararelo中调用两个或更多Web服务或Rest服务并撰写调用的响应。
我在网上发现了一些使用其他技术的例子,但我不能让它与反应堆一起工作
// start task A asynchronously
CompletableFuture<ResponseA> futureA = asyncServiceA.someMethod(someParam);
// start task B asynchronously
CompletableFuture<ResponseB> futureB = asyncServiceB.someMethod(someParam);
CompletableFuture<String> combinedFuture = futureA
.thenCombine(futureB, (a, b) -> a.toString() + b.toString());
// wait till both A and B complete
String finalValue = combinedFuture.join();
/////////////////////////////////////////////// /////////////////////////////////
static void Run()
{
//Follow steps at this link for addding a reference to the necessary .NET library:
//http://stackoverflow.com/questions/9611316/system-net-http-missing-from-
//namespace-using-net-4-5
//Create an HTTP Client
var client = new HttpClient();
//Call first service
var task1 = client.GetAsync("http://www.cnn.com");
//Call second service
var task2 = client.GetAsync("http://www.google.com");
//Create list of all returned async tasks
var allTasks = new List<Task<HttpResponseMessage>> { task1, task2 };
//Wait for all calls to return before proceeding
Task.WaitAll(allTasks.ToArray());
}
答案 0 :(得分:2)
让我们假设你需要点击2个服务,所以你需要2个基础 <my-typeahead-control formControlName="item" [items]="allItemsArray" itemLabelKey="name"></my-typeahead-control>
(每个都配置了正确的基本URL,例如一个身份验证方案):
WebClient
从那里开始,假设您在控制器中注入了这两个Web客户端(作为限定的 bean)。这是使用Reactor联合调用两个代码的代码:
@Bean
public WebClient serviceAClient(String authToken) {
return WebClient.builder()
.baseUrl("http://serviceA.com/api/v2/")
.defaultHeader(HttpHeaders.AUTHORIZATION, "Basic " + authToken)
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
}
@Bean
public WebClient serviceBClient(String authToken): WebClient {
return WebClient.builder()
.baseUrl("https://api.serviceB.com/")
.defaultHeader(HttpHeaders.AUTHORIZATION, "token " + authToken)
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
}
请注意,zip函数可以生成更有意义的内容,就像2个响应中的业务对象一样。结果Mono<ResponseA> respA = webclientA.get()
.uri("/sub/path/" + foo)
.retrieve()
.bodyToMono(ResponseA.class);
Mono<ResponseB> respB = webclientB.get()
.uri("/path/for/b")
.retrieve()
.bodyToMono(ResponseB.class);
Mono<String> join = respA.zipWith(respB, (a, b) -> a.toString + b.toString);
return join;
只会触发2个请求,如果有东西订阅它(在Spring WebFlux的情况下,如果从控制器方法返回它,框架会这样做)。
答案 1 :(得分:1)
如果您正在使用Spring reactor,那么您需要的是运营商Zip,以便运行您的流程并将其压缩一次。
/**
* Zip operator execute the N number of Flux independently, and once all them are finished, results
* are combined in TupleN object.
*/
@Test
public void zip() {
Flux<String> flux1 = Flux.just("hello ");
Flux<String> flux2 = Flux.just("reactive");
Flux<String> flux3 = Flux.just(" world");
Flux.zip(flux1, flux2, flux3)
.map(tuple3 -> tuple3.getT1().concat(tuple3.getT2()).concat(tuple3.getT3()))
.map(String::toUpperCase)
.subscribe(value -> System.out.println("zip result:" + value));
}
您可以在此处查看有关反应技术的更多信息https://github.com/politrons/reactive
答案 2 :(得分:0)
如果您已经有一个同步实现,则可以借助Mono.fromCallable()
方法轻松添加一些反应堆功能使其并行运行。
Mono<ResponseA> responseA = Mono
.fromCallable(() -> blockingserviceA.getResponseA())
.subscribeOn(Schedulers.elastic()); // will execute on a separate thread when called
Mono<ResponseB> responseB = Mono
.fromCallable(() -> blockingserviceB.getResponseB())
.subscribeOn(Schedulers.elastic());
// At that point nothing has been called yet, responseA and responseB are empty Mono
AggregatedStuff aggregatedStuff = Mono.zip(responseA, responseB) // zip as many Mono as you want
.flatMap(r -> doStuff(r.getT1(), r.getT2())) // do whatever needed with the results
.block(); // execute the async calls, and then execute flatMap transformation
fromCallable()
和just()
之间需要注意的重要一点是,just()
将直接在主线程中执行,但是fromCallable()
是懒惰的表示仅在需要时才执行,例如:当您调用block(),collect()(对于Flux),...等...
Mono<ResponseA> responseA = Mono
.just(blockingserviceA.getResponseA()) // execute directly
Mono<ResponseB> responseB = Mono
.just(blockingserviceB.getResponseB()) // execute directly
// Above code have been executed sequentially, you can access response result
// => yes it is kind of useless, and yes it is exactly how I did it the first time!
因此,避免将just()
用于要并行运行的繁重任务。使用just()
进行实例化是完全正确的,因为您不想在每次实例化String或任何其他对象时都创建新线程并获得随之而来的开销。
PS:正如SimonBaslé所指出的,您可以使用WebClient直接返回Mono和Flux并进行异步调用,但是如果您已经实现了api客户端,并且无法选择重构整个应用程序,{{1 }}是设置异步过程而无需重构大量代码的简单方法。