抱歉,如果之前有人问过,但我没有找到匹配的问题。
我有一个执行API调用其他服务的应用程序。我正在考虑使用Spring建议的WebClient over RestTemplate。我正在执行专门的同步调用。我知道WebClient的设计思想是React式的。但理论上,只使用WebClient来阻塞调用是否合适?我担心的是,每次调用时都必须调用.block()
来获取数据。所以我的问题是:
1.使用.block()
的安全性如何?在WebClient中阻塞线程通常是否可以?
1.使用WebClient阻塞调用背后的机制与RestTemplate类似吗?
1.是否有可能性能会比我只使用RestTemplate的情况更差?
先谢了!
3条答案
按热度按时间jgwigjjp1#
由于似乎有误解,我将尽力回答我所知道的最好的问题。
使用.block()的安全性如何?通常在WebClient中阻塞线程是否可以?
阻塞总是“安全的”,但是它是否影响性能是另一回事。当一个请求进来时,它被分配了一个线程。当我们使用
RestTemplate
执行一个请求时,同一个线程将执行外部请求,RestTemplate
将在引擎盖下阻塞该线程以等待响应。这绝不是线程的有效使用,但它是完全“安全”的,这是大多数Web服务器在过去20年中的工作方式。
在非响应式应用程序中使用
WebClient
时,您阻止了Mono<T>
(实际上您将这样做)框架将首先检查线程是否是允许阻塞的线程类型(不是nio线程),之后它使用CountDownLatch
,在CountDownLatch#await
暂停/阻塞调用线程,直到第一个onNext/onComplete/onError信号到达。在阻塞应用程序中完全可以使用。2你可以在这里找到相关的代码。当你把
WebClient
添加到类路径中时,你会自动得到netty作为底层服务器,这一点很好了解,如果你想改变它,那么你需要明确它。此外,建议您在执行多个请求时,在诉诸
block
之前尽可能多地链接响应式呼叫。如果你想转移到一个被动的应用程序,那么这是一个很好的慢慢转移应用程序的方法,慢慢地做越来越被动的事情,然后调用
block
回到 * 常规 * 世界。你完全被动吗?不,你是一个阻塞的网络服务器像以前一样,嗯,是的。这是更糟的
RestTemplate
最有可能不是。你比以前更好,从维护的Angular 来看,是的,因为Spring已经正式走了,不会有任何更多的更新RestTemplate
。使用WebClient阻塞调用背后的机制与RestTemplate类似吗?
这很难说,因为
RestTemplate
主要是底层服务器实现提供的HttpClient
的 Package 器。编写阻塞的方式可能不同,但它们最后的操作很可能是相同的。
Mono<T>
阻塞使用CountDownLatch
,重复调用getCount
,然后在块之间调用锁存器await
,直到响应返回。我还没有查看RestTemplate
Package 的不同HttpClient,你需要仔细阅读他们中的每一个(雄猫,码头,undertow,等等)是否有可能性能会比我只使用RestTemplate的情况更差?
这很难讲,因为性能不是白色的,它完全取决于硬件、要完成的任务类型、代码编写方式、线程池大小、操作系统等。
Netty
是一个完全事件驱动的服务器,它开始成为Java社区中Web服务器的事实标准。Undertow decided to switch out their entire core to thenetty core
,因为它非常好,而且更容易维护。由于
Netty
是事件驱动的,因此将其作为一个 * 旧 * 服务器运行,每个请求一个线程可能会损害性能,因为它没有针对这种类型的工作进行优化,但另一方面,当您完全事件驱动地运行它时,它会大放异彩。回答这个问题的唯一方法是制定自己的基准,我们无法为您回答。
如果你想知道更多关于netty实际上是如何工作的,建议阅读Netty in Action这本书,它不是免费的,但非常好读,以了解
Netty
的内部工作原理和它的async
线程模型。iqjalb3h2#
在我们的应用程序中,我们从RestTemplate迁移到WebClient没有任何问题,.block()工作正常
这与RestTemplate所做的相同,它以同步方式发送请求,我们让它在PROD中工作了几个月,没有出现任何问题
xxe27gdn3#
如果您想在只使用
spring-boot-starter-webflux
依赖项的情况下以阻塞方式使用webClient,则会抛出类似block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-3
的异常,因此,为了以阻塞方式使用WebClient,您需要通过添加文档Web环境中所述的spring-boot-starter-web来配置spring MVC应用程序,这一点值得添加到前面的响应中:SpringApplication尝试代表您创建正确类型的ApplicationContext。用于确定WebApplicationType的算法如下:
如果存在Spring MVC,则使用注解配置Servlet Web服务器应用程序上下文
如果Spring MVC不存在而Spring WebFlux存在,则使用AnnotationConfigReactiveWebServerApplicationContext
否则,将使用AnnotationConfigApplicationContext
这意味着如果您在同一个应用程序中使用Spring MVC和来自Spring WebFlux的新WebClient,则默认情况下将使用Spring MVC,您可以通过调用setWebApplicationType(WebApplicationType)轻松覆盖它。