我应该让我的 REST 客户端 API 库异步(Java 8)
Posted
技术标签:
【中文标题】我应该让我的 REST 客户端 API 库异步(Java 8)【英文标题】:Should I make my REST client API library Async (Java 8) 【发布时间】:2020-09-18 03:40:54 【问题描述】:我正在为我们的 REST 服务器创建客户端库。对于 C# 库,我使用 HttpClient.PostAsync() 效果很好,它返回一个对象,调用者可以等待(使其同步),他们可以完成一些其他操作然后等待,或者他们可以使用 C# 等待机制。很好的解决方案。
对于 Java,我必须为 Java 8 编写库,因为这是使用最多的版本。使用 Java 8,我们覆盖了 98% 的程序员。 (如果我们有足够的需求,我也会做一个 Java 11 的,然后我们有本地异步调用。)
所以这是我的问题,There are ways to get async behavior,使用 DeferredResult 或一些 3rd 方类。但是我围绕这个构建我的 API 并强制它有什么好处吗?因为如果我创建一个同步 API,调用者仍然可以在他们自己的 DeferredResult 代码中调用它。这是相同的最终结果。
所以在我看来,提供一个简单直接的 API 的方法是提供一个同步的。而那些想要异步的人将其包装在他们喜欢使其异步的任何机制中。这里的一个重要优势是我不会强制使用他们不使用的机制或第 3 方库。
这种方法有什么缺点吗?
更新:这里更详细。
如果我只有一个同步 API,那么调用者可以包装我的同步 API in many different ways。最简单的使用 vanilla Java 8 是:
// API is: public Metrics postMetrics(Template template)
CompletableFuture<Metrics> completableFuture = CompletableFuture.supplyAsync(() -> return client.postMetrics(template); );
如果我创建一个异步 API,那么我将选择这些方法中的哪一种(我将使用 CompletableFuture),因此 API 变为:
// API is: public CompletableFuture<Metrics> postMetrics(Template template)
CompletableFuture<Metrics> completableFuture = client.postMetricsAsync(template);
当然,使用异步 API 会更容易一些。但差别很小。不利的一面是我现在对它们强制使用异步方法。我是否错过了提供异步 API 的更大优势?
【问题讨论】:
如果您真的想要时尚和现代,当前的方法是使用响应式堆栈(可能使用WebClient
)。
@chrylis-cautiouslyoptimistic- 因为我们是一个图书馆,客户会添加到他们的项目中,所以我试图尽可能轻松地融入他们的堆栈。在我们所有的客户中,这意味着几乎任何你能想象到的堆栈,还有一些你从未听说过的堆栈。
【参考方案1】:
最终结果不一样。
同步 I/O 会为阻塞线程消耗大量内存。这是同步方法的主要缺点。将同步 I/O 设为主要,您的异步 I/O 仍然需要同步 I/O,因此会消耗大量资源。
合理的方法是使异步接口成为主要的,并用同步方法对其进行扩充。然后,用户可以选择是否有能力为阻塞线程花费内存或使用最少的资源使用多个 I/O 操作。
【讨论】:
好吧,我有些不明白。因为如果我使用 DeferredResult 创建一个异步 API,我仍然在那个(Java 8)中进行同步调用,不是吗?在这种情况下,它会立即返回,因此代码可以做其他事情,但在初始调用中有一个同步调用等待响应。不是这样吗? DeferredResult 是真正异步的,内部不包含任何同步调用,除非您显式调用 DeferredResult.getResult()。我建议在你的 API 中公开它,它已经有同步和异步接口,你不需要围绕它做额外的层。 我想在某个地方,某事,不知何故总是在等待 API 调用的结果回来。它可能位于远离 DEV 用来进行调用的实际层中,但仍有一些东西在等待结果返回。 我只是提出了我认为的两种不同方法。我是否遗漏了异步 API 可以提供的东西? @AlexeiKaigorodov 必须调用回调过程。作为一名开发人员,我不调用回调并希望在异步操作完成时调用它。调用它的代码必须在等待结果,对吧?还是我都搞错了。【参考方案2】:也许你应该从这些方面考虑,如果明天有另一个竞争库提供开箱即用的异步行为和同步呢?
如果我是一名开发人员,我可能会选择一个允许我开箱即用的异步行为并提供配置选项的选项。
我所说的只有在您考虑易于开发人员采用和内置易于进行异步 API 调用时才有意义。
我希望这会有所帮助。
【讨论】:
我刚刚添加了一个列出代码差异的更新。你更喜欢它强制使用一种异步方法吗? clientBuilder.build() 提供客户端的同步版本,但 clientBuilder.Async().build() 提供异步客户端。那些想要 aync 但不是 clientBuilder.Async().build() 给出的默认值的人可以根据需要包装 clientBuilder.build() 。这样您就不会强制使用特定的方式,而是提供可靠的默认值和自定义的灵活性。以上是关于我应该让我的 REST 客户端 API 库异步(Java 8)的主要内容,如果未能解决你的问题,请参考以下文章
使用 Redux Toolkit 异步 REST API 模式时如何捕获 HTTP 4xx 错误?
REST - API客户端应该像浏览器一样“前进”到“下一个”资源吗?