tau*_*sif 7 java event-driven reactive-programming vert.x
我有一种情况,我调用外部API A并使用其响应来提供API B的请求并调用它,然后将响应返回给API A的调用者.如下所示
method(){
response = call API A
}
method_for_API_A(){
handler() ->{
API_B
}
return response;
}
method_for_API_B(){
//code to call API B
}
Run Code Online (Sandbox Code Playgroud)
我在这里面临的是API A方法返回响应而不等待从B获得响应.
我检查了vert.x的executeBlocking方法,并尝试使用'阻塞队列',但无法实现我打算做的事情.有人可以指导我做正确的方法.谢谢.
编辑:只是解释确切的情况
Class MyClass{
public Response method_A (Request request){
String respFromApiA = Call_API_A(request) ; // STEP 1
Response respFromApiB = Call_API_B(request, respFromApiA); // STEP 2
Print(respFromApiB) // PRINT FINAL Response
return respFromApiB; // STEP 3
}
String Call_API_A(Request request){
// Implementation
Print(string); // PRINT API A response
return string
}
Response Call_API_B(Response response){
// Implementation
Print(response); // PRINT API B response
return response;
}
}
Run Code Online (Sandbox Code Playgroud)
我在使用Vert.x框架和Java.现在执行期间发生的是,流程进入步骤1,启动API A调用.转到步骤2(不等待'respFromApiA')并调用API B(最终因为respFromApiA为NULL而失败).最后流程进入第3步并从此处返回.(无需等待API A和API B的结果).如果我们看到打印订单,它将是这样的
PRINT FINAL Response
PRINT API A response
PRINT API B response
Run Code Online (Sandbox Code Playgroud)
我想要实现的目标是什么?
Wait for API A response.
Make call to API B. Wait for API B response.
Return response got from API B.
Run Code Online (Sandbox Code Playgroud)
我希望这次我能说清楚.如果您需要进一步的输入,请告诉我.
ale*_*ter 15
Vert.x是高度异步的.事实上,大多数操作将立即返回,但其结果将Handler在稍后的时间点提供.到现在为止还挺好.如果我理解正确,你比你需要调用B中Handler的A.在这种情况下A需要完成并在调用之前结果可用B:
callA(asyncResultA -> {
System.out.println("Result A: " + asyncResultA.result());
callB(asyncResultB -> {
System.out.println("Result B:" + asyncResultB.result());
});
});
Run Code Online (Sandbox Code Playgroud)
但你正在尝试的是使异步同步.您不能也不应该尝试在主程序流中提供异步结果 - 这是行不通的.
String respFromApiA = Call_API_A(request); // STEP 1
Response respFromApiB = Call_API_B(request, respFromApiA); // STEP 2
Print(respFromApiB); // PRINT FINAL Response
return respFromApiB; // STEP 3
Run Code Online (Sandbox Code Playgroud)
Call_API_A无法真正返回结果,因为它是异步计算的.其结果是仅适用于Handler的Call_API_A(见上面我的例子).相同Call_API_B- 所以你不能返回结果Call_API_B.你班上的来电者也需要用你的班级来打电话Handler.
现在一些额外的信息.在您的情况下,您遇到的问题是多个异步结果相互依赖.Vert.x提供了一种处理异步结果的更方便的方法 - 所谓的Futures.A Future(有时Promise在Java世界中称为它们被调用Future)是异步调用结果的占位符.在文档中阅读它们.
有了Future你可以做这样的事情:
Future<...> callAFuture = Future.future();
callA(asyncResultA -> {
if (asyncResultA.succeeded()) {
System.out.println("A finished!");
callAFuture.complete(asyncResultA.result());
} else {
callAFuture.fail(asyncResultA.cause());
}
});
Run Code Online (Sandbox Code Playgroud)
因此,而不是试图返回异步结果B以同步的方式,你应该返回一个Future类,这样被叫方可以为双方的异步结果寄存器A和B.
我希望这有帮助.
编辑:未来作为返回值
让我们说你想要包装callA,这样你就可以使用Future.你可以这样做:
public Future<String> doSomethingAsync() {
Future<String> callAFuture = Future.future();
// do the async stuff
callA(asyncResultA -> {
if (asyncResultA.succeeded()) {
System.out.println("A finished!");
callAFuture.complete(asyncResultA.result());
} else {
callAFuture.fail(asyncResultA.cause());
}
});
// return Future with the asyncResult of callA
return callAFuture;
}
Run Code Online (Sandbox Code Playgroud)
此函数的调用者可以像这样使用Future:
Future<String> doSomethingFuture = doSomethingAsync();
doSomethingFuture.setHandler(somethingResult -> {
// ... doSomethingAsync finished
});
Run Code Online (Sandbox Code Playgroud)
Future如果你想同时执行它们,也可以组合多个但是它们不相互依赖:
CompositeFuture.all(futureA, futureB).setHandler(connections -> {
// both Futures completed
});
Run Code Online (Sandbox Code Playgroud)
如果你像大多数Vert.x的时候,你有工作异步环境中工作即将成为可用,因此又名Future.而在Handler一个Future你经常做另一个异步调用.你一包Future用Future类似的例子callB中callA的Handler.
您如何将FutureHTTP 的异步结果作为HTTP响应返回?像这样:
router.route("/").handler(routingContext -> {
HttpServerResponse response = routingContext.response();
Future<String> future = doSomethingAsync();
future.setHandler(somethingResult -> {
if (somethingResult.succeeded()) {
response
.end(somethingResult.result());
} else {
routingContext.fail(500);
}
});
});
Run Code Online (Sandbox Code Playgroud)
我曾经Future返回一些 results以在其他方法中再次使用它,这是我的实现,我希望它可以帮助某人:
public static void ussdMessages(RoutingContext routingContext){
String codeService = routingContext.getBodyAsJson().getString("codeService");
Future<String> futureQuery=getServiceQuery(codeService);
Future<JsonObject> futureParams = getServiceParams(codeService);
CompositeFuture.all(futureQuery,futureParams).setHandler(r->{
System.out.println(futureQuery.result());
System.out.println(futureParams.result());
});
}
public static Future<JsonObject> getServiceParams(String codeService){
Future<JsonObject> future=Future.future();
JsonObject params = new JsonObject();
params.put("QUERY", Queries.DB_SELECT_SERVICE_PARAMS);
params.put("PARAMS", new JsonArray().add(codeService));
DB.select(params, res -> {
if (res.succeeded()) {
future.complete(res.result());
} else {
future.fail(res.cause().getMessage());
}
});
return future;
}
public static Future<String> getServiceQuery(String codeService){
Future<String> future = Future.future();
JsonObject params = new JsonObject();
params.put("QUERY", Queries.DB_SELECT_SERVICE_QUERY);
params.put("PARAMS", new JsonArray().add(codeService));
System.out.println(params);
DB.select(params, res -> {
if (res.succeeded()) {
// query = res.result().getJsonArray("results").getJsonArray(0).getString(0);
future.complete(res.result().getJsonArray("results").getJsonArray(0).getString(0));
} else {
future.fail(res.cause().getMessage());
}
});
return future;
}
Run Code Online (Sandbox Code Playgroud)