我正在尝试使用 Spring boot 开发示例 Rest API 应用程序来测试我的 java 客户端库(这是 JS 客户端的转换)。 Java 客户端执行一些异步任务并返回响应作为回调。
这是我如何从示例应用程序的服务中调用它的示例。
@Async
public void initializeUser(InitRequest initRequest) {
String BASE_URL = "http://sample_url";
client.initUser(BASE_URL, initRequest, new ResponseCallback<InitRequest>() {
@Override
public void onSuccess(@NonNull InitRequest arg0) {
// Return arg0 to controller
System.out.println("User Initialized: " + arg0.getId());
}
@Override
public void onError(@NonNull ResponseBody error) {
// Return error to controller
System.out.println("User Initialize failed");
}
@Override
public void validationError(@NonNull String arg0) {
// return validationError to controller
// TODO Auto-generated method stub
}
});
}
这里 initUser 是在我的客户端中实现的方法。当我从控制器调用此方法时。控制器在实际请求完成之前返回,我在邮递员中看不到任何响应。
这是一个控制器方法。
@RequestMapping(method=RequestMethod.POST, value = "/init" )
public void initUser( @RequestBody InitRequest initRequest) {
experimentServices.initializeUser(initRequest);
// wait for request to finish and send response to user
}
就像在 javascript 中一样,我可以使用 Promise 或 async/await 等待服务给出响应,然后再返回给用户。
我想知道......
1)如何在Java中实现类似的功能? (服务将一些数据返回给控制器,然后将其作为对最终用户的响应)。
2) Java 方法需要特定的返回响应,而服务可能会给出 Error、ValidationError 或 Successl 响应对象。有没有办法在一个函数中正确处理所有这些?
任何链接或文档都会有帮助。 谢谢
在您的代码中,您异步调用的方法是一个 void 方法,这意味着它不会返回任何内容。在 Spring 中,使用
@Async
注释 bean 的方法将使其在单独的线程中执行,即调用者将不等待被调用方法的完成。
所以,如果你想让控制器等待执行完成,如果你想等待结果我建议你使用
Future
。您可以采取将实际返回包装在 Future
实例中的方法。我还没有尝试编译此代码,但如下所示:
@Async
public Future<T> initializeUser(InitRequest initRequest) {
String BASE_URL = "http://sample_url";
client.initUser(BASE_URL, initRequest, new ResponseCallback<InitRequest>() {
@Override
public void onSuccess(@NonNull InitRequest arg0) {
return new AsyncResult<InitRequest>(arg0);
System.out.println("User Initialized: " + arg0.getId());
}
@Override
public void onError(@NonNull ResponseBody error) {
return new AsyncResult<ResponseBody>(error);
System.out.println("User Initialize failed");
}
@Override
public void validationError(@NonNull String arg0) {
return new AsyncResult<String>(arg0);
// TODO Auto-generated method stub
}
});
}
并在其余控制器中接收此信息:
@RequestMapping(method=RequestMethod.POST, value = "/init" )
public InitRequest initUser( @RequestBody InitRequest initRequest) {
Future<T> futureResult = experimentServices.initializeUser(initRequest);
// wait for request to finish and send response to user
if (futureResult.isDone()) {
return futureResult.get();
}
}
最好的方法是避免服务器忙于等待,所以使用 DeferredResult:
private ExecutorService executor = ....
@RequestMapping(method=RequestMethod.POST, value = "/init" )
public DeferredResult<ResponseEntity<InitResponse>> initUser(@RequestBody InitRequest initRequest) {
final DeferredResult<ResponseEntity<InitResponse>> output = new DeferredResult<>(5000L, 5000L);
executor.submit(() -> {
InitResponse response = processAndcreateRespnse(...);
output.setResult(new ResponseEntity<>(response, HttpStatus.OK));
});
return output;
}