Это один из очень немногих случаев использования, когда вам действительно разрешено вызывать нереактивные библиотеки и заключать их в реактивные типы, а обработка выполнялась в операторах побочных эффектов, таких как doOnXYZ
, потому что:
- Кофеин - это кэш в памяти, поэтому, насколько я знаю, в этом нет ввода-вывода
- Кеши часто не дают надежных гарантий относительно значений кэширования (это очень многои забудьте)
В этом случае вы можете запросить кэш, чтобы увидеть, есть ли в нем кэшированная версия (обернуть ее и вернуть сразу), и кэшировать успешный реальный ответ в операторе doOn
, например так:
public class MyService {
private WebClient client;
private Cache<MyRequestObject, MyResponseObject> myCaffeineCache;
public MyService() {
this.client = WebClient.create();
this.myCaffeineCache = Caffeine.newBuilder().maximumSize(100)
.expireAfterWrite(Duration.ofSeconds(60)).build();
}
public Mono<MyResponseObject> fetchResponse(MyRequestObject request) {
MyResponseObject cachedVersion = this.myCaffeineCache.get(myRequestObject);
if (cachedVersion != null) {
return Mono.just(cachedVersion);
} else {
return this.client.post()
.uri("http://www.example.com")
.syncBody(request.getKey())
.retrieve()
.bodyToMono(MyResponseObject.class)
.doOnNext(response -> this.myCaffeineCache.put(request.getKey(), response));
}
}
Обратите внимание, что я не буду кэшировать реактивные типы здесь, поскольку здесь нет ни операций ввода-вывода, ни обратного давления после возврата значения из кэша. Наоборот, это делает вещи болеесложно с подпиской и другими ограничениями реактивных потоков.
Также вы правы насчет оператора cache
, поскольку речь идет не о кэшировании значения как такового, а от воспроизведение того, что случилось с другими подписчиками.Я считаю, что операторы cache
и replay
на самом деле являются синонимами для Flux
.