Как управляется элемент кэша пружинного потока - PullRequest
0 голосов
/ 04 сентября 2018

Рассмотрим пример кода:

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));
    }
}

Спецификация говорит :

Сохраняет неограниченную историю, но применяет время истечения для каждого элемента

Что такое элемент и что кешируется?

  1. Весь http-вызов кэшируется. Например. если я вызову цепочку методов .get().uri() с id = 1, то любые последующие вызовы будут кэшироваться? или
  2. Только Mono<MyClass> кэшируется. Например. любой последующий вызов Mono.map будет использовать кэшированное значение?

В обоих случаях, что считается предметом?

1 Ответ

0 голосов
/ 05 сентября 2018

Оператор cache в Reactor очень отличается от чего-то вроде аннотации @Cacheable в компонентном методе.

Например, аннотация @Cacheable будет:

  • перехватывает вызовы методов и вычисляет ключ кеша из параметров метода
  • вызов метода и сохранение результата во внешнем кэше
  • предоставляет кэшированный результат всякий раз, когда другой метод вызывает этот метод с теми же параметрами

Все операторы Reactor являются декораторами, они возвращают новый экземпляр Flux / Mono - , поэтому вам нужно связать операторы .

Давайте рассмотрим этот пример:

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 секунд (а затем перейдите к остальным) для всех новых подписок.

...