考虑代码示例:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import java.time.Duration;
import static com.google.common.collect.ImmutableMap.of;
@Component
public class Scratch {
@Autowired
private WebClient webClient;
public Mono<MyClass> getMyClass(Long id) {
return webClient.get()
.uri("{id}", of("id", id))
.retrieve()
.bodyToMono(MyClass.class)
.cache(Duration.ofHours(1));
}
}
规范tells:
将保留无限制的历史记录,但应用每个项目的到期超时
什么是项目和什么是缓存?
.get().uri()
调用方法链id = 1
,任何后续调用都将被缓存?要么Mono<MyClass>
被缓存。例如。对Mono.map
的任何后续调用都将使用缓存值?在这两种情况下,什么被视为项目?
Reactor中的cache
运算符与组件方法上的@Cacheable
注释非常不同。
例如,@Cacheable
注释将:
所有Reactor运算符都是装饰器,它们返回Flux
/ Mono
的新实例 - this is why you need to chain operators。
我们来看这个例子:
Scratch scratch = //...
Mono<MyClass> myClass = scratch.getMyClass(12L);
这意味着每次订阅特定的Mono
实例(因此不是scratch.getMyClass(44L);
,也不是另一个scratch.getMyClass(12L);
调用返回的任何其他实例)时,Reactor将返回第一次使用时缓存的元素。
当Reactor谈论元素时,那些是MyClass
消息的实例;因为在这里,在bodyToMono
之后添加了缓存操作符。如果您要在管道中的其他位置添加该运算符,那将是一个不同的故事,即它会缓存不同的东西。
现在,这不是为所有类似的HTTP调用实现HTTP客户端缓存的功能。如果应用程序的多个部分需要完全相同的数据,并且您不想浪费资源反复获取相同的内容,则此功能非常有用。
例如,假设这个HTTP调用很昂贵,你想在几个地方使用那个MyClass
实例:
Mono<MyClass> myClass = scratch.getMyClass(12L);
Mono<Void> result = saveToDatabase(myClass).then(calculateStats(myClass));
另一个用例是,当您想要将数据流共享给多个客户端时:
@RestController
public class StreamingController {
private Flux<StockQuotes> quotes = quoteService.fetch().cache(Duration.ofSeconds(5));
@GetMapping("/quotes")
public Flux<StockQuotes> streamQuotes() {
return this.quotes;
}
在这种情况下,每当新的HTTP客户端请求服务器并从中传输数据时,服务器将不会创建与远程库存服务的新连接,并将重放最后5秒的报价(然后继续所有新订阅。