Введение в Spring Data Redis Reactive

Введение в Spring Data Redis Reactive

1. Вступление

В этом руководствеwe’re going to learn how to configure and implement Redis operations using Spring Data’s ReactiveRedisTemplate. 

Мы рассмотрим основные способы использованияReactiveRedisTemplate, например, как хранить и извлекать объекты в Redis. И мы рассмотрим, как выполнять команды Redis с помощьюReactiveRedisConnection.

Чтобы охватить основы, ознакомьтесь с нашимIntroduction to Spring Data Redis.

2. Настроить

Чтобы использоватьReactiveRedisTemplate in в нашем коде, сначала нам нужно добавить модульdependency for Spring Boot’s Redis Reactive:


    org.springframework.boot
    spring-boot-starter-data-redis-reactive

3. конфигурация

Затемwe необходимо установить соединение с нашим сервером Redis. Нам не нужно добавлять какой-либо код для конфигурации, если мы хотим подключиться к серверу Redis вlocalhost:6379.

Но,if our server were remote or were on a different port, we could supply the hostname and port in the LettuceConnectionFactory constructor:

@Bean
public ReactiveRedisConnectionFactory reactiveRedisConnectionFactory() {
    return new LettuceConnectionFactory(host, port);
}

4. Список операций

Списки Redis - это списки строк, отсортированные по порядку вставки. Мы можем добавлять или удалять элементы из списка, нажимая или щелкая их слева или справа.

4.1. Шаблон строки

Для работы со списками нам понадобится экземплярReactiveRedisTemplate that we’ve provided a String serialization context:

@Bean
public ReactiveRedisTemplate reactiveRedisTemplateString
  (ReactiveRedisConnectionFactory connectionFactory) {
    return new ReactiveRedisTemplate<>(connectionFactory, RedisSerializationContext.string());
}

И из только что созданного шаблона String мы можем получить экземплярReactiveListOperations:

@Autowired
private ReactiveRedisTemplate redisTemplate;

private ReactiveListOperations reactiveListOps;

@Before
public void setup() {
    reactiveListOps = redisTemplate.opsForList();
}

4.2. ЛПУШ и ЛПОП

Теперь, когда у нас есть экземплярReactiveListOperations,, давайте выполним операцию LPUSH для списка сdemo_list в качестве идентификатора списка.

После этого мы выполним LPOP для списка, а затем проверим, что элемент появился:

@Test
public void givenListAndValues_whenLeftPushAndLeftPop_thenLeftPushAndLeftPop() {
    Mono lPush = reactiveListOps.leftPushAll(LIST_NAME, "first", "second")
      .log("Pushed");

    StepVerifier.create(lPush)
      .expectNext(2L)
      .verifyComplete();

    Mono lPop = reactiveListOps.leftPop(LIST_NAME)
      .log("Popped");

    StepVerifier.create(lPop)
      .expectNext("second")
      .verifyComplete();
}

Обратите внимание, что при тестировании реактивных компонентов мы можем использоватьStepVerifier для блокировки завершения задачи.

5. Ценностные операции

Мы можем захотеть использовать и пользовательские объекты, а не только строки.

Итак, давайте проделаем некоторые аналогичные операции с объектомEmployee, чтобы продемонстрировать наши операции с POJO:

public class Employee implements Serializable {
    private String id;
    private String name;
    private String department;

    // ... getters and setters

    // ... hashCode and equals
}

5.1. Шаблон сотрудника

Нам нужно будет создать второй экземплярReactiveRedisTemplate.. Мы по-прежнему будем использоватьString  для нашего ключа, но на этот раз значение будетEmployee:

@Bean
public ReactiveRedisTemplate reactiveRedisTemplate(
  ReactiveRedisConnectionFactory factory) {

    StringRedisSerializer keySerializer = new StringRedisSerializer();
    Jackson2JsonRedisSerializer valueSerializer =
      new Jackson2JsonRedisSerializer<>(Employee.class);
    RedisSerializationContext.RedisSerializationContextBuilder builder =
      RedisSerializationContext.newSerializationContext(keySerializer);
    RedisSerializationContext context =
      builder.value(valueSerializer).build();

    return new ReactiveRedisTemplate<>(factory, context);
}

Чтобы правильно сериализовать пользовательский объект, нам нужно проинструктировать Spring, как это сделать. Здесь мы сообщили шаблонуuse the Jackson library by configuring a Jackson2JsonRedisSerializer for the value. Поскольку ключ - это просто строка, мы можем использовать для этогоStringRedisSerializer .

Затем мы берем этот контекст сериализации и нашу фабрику соединений для создания шаблона, как и раньше.

Затем мы создадим экземплярReactiveValueOperations, как мы делали ранее сReactiveListOperations:

@Autowired
private ReactiveRedisTemplate redisTemplate;

private ReactiveValueOperations reactiveValueOps;

@Before
public void setup() {
    reactiveValueOps = redisTemplate.opsForValue();
}

5.2. Операции сохранения и восстановления

Теперь, когда у нас есть экземплярReactiveValueOperations, let, используйте его для хранения экземпляраEmployee:

@Test
public void givenEmployee_whenSet_thenSet() {

    Mono result = reactiveValueOps.set("123",
      new Employee("123", "Bill", "Accounts"));

    StepVerifier.create(result)
      .expectNext(true)
      .verifyComplete();
}

И тогда мы можем получить тот же объект обратно из Redis:

@Test
public void givenEmployeeId_whenGet_thenReturnsEmployee() {

    Mono fetchedEmployee = reactiveValueOps.get("123");

    StepVerifier.create(fetchedEmployee)
      .expectNext(new Employee("123", "Bill", "Accounts"))
      .verifyComplete();
}

5.3. Операции со сроком действия

Мы часто хотимput values in a cache that will naturally expire, и мы можем сделать это с той же операциейset :

@Test
public void givenEmployee_whenSetWithExpiry_thenSetsWithExpiryTime()
  throws InterruptedException {

    Mono result = reactiveValueOps.set("129",
      new Employee("129", "John", "Programming"),
      Duration.ofSeconds(1));

    StepVerifier.create(result)
      .expectNext(true)
      .verifyComplete();

    Thread.sleep(2000L);

    Mono fetchedEmployee = reactiveValueOps.get("129");
    StepVerifier.create(fetchedEmployee)
      .expectNextCount(0L)
      .verifyComplete();
}

Обратите внимание, что этот тест выполняет некоторые собственные блокировки, ожидая истечения срока действия ключа кэша.

6. Команды Redis

Команды Redis - это в основном методы, которые клиент Redis может вызывать на сервере. И Redis поддерживает десятки команд, некоторые из которых мы уже видели, например LPUSH и LPOP.

Operations API - это абстракция более высокого уровня вокруг набора команд Redis.

Однакоif we want to use the Redis command primitives more directly, then Spring Data Redis Reactive also gives us a Commands API.

Итак, давайте посмотрим на команды String и Key через призму APICommands.

6.1. Строковые и ключевые команды

Для выполнения командных операций Redis мы получим экземплярыReactiveKeyCommands иReactiveStringCommands.

Мы можем получить их обоих из нашего экземпляраReactiveRedisConnectionFactory:

@Bean
public ReactiveKeyCommands keyCommands(ReactiveRedisConnectionFactory
  reactiveRedisConnectionFactory) {
    return reactiveRedisConnectionFactory.getReactiveConnection().keyCommands();
}

@Bean
public ReactiveStringCommands stringCommands(ReactiveRedisConnectionFactory
  reactiveRedisConnectionFactory) {
    return reactiveRedisConnectionFactory.getReactiveConnection().stringCommands();
}

6.2. Установить и получить операции

Мы можем использоватьReactiveStringCommands для хранения нескольких ключей с одним вызовомbasically invoking the SET command multiple times.

А затем мы можем получить эти ключи черезReactiveKeyCommands,invoking the KEYS command:

@Test
public void givenFluxOfKeys_whenPerformOperations_thenPerformOperations() {
    Flux keys = Flux.just("key1", "key2", "key3", "key4");
      .map(String::getBytes)
      .map(ByteBuffer::wrap)
      .map(key -> SetCommand.set(key).value(key));

    StepVerifier.create(stringCommands.set(keys))
      .expectNextCount(4L)
      .verifyComplete();

    Mono keyCount = keyCommands.keys(ByteBuffer.wrap("key*".getBytes()))
      .flatMapMany(Flux::fromIterable)
      .count();

    StepVerifier.create(keyCount)
      .expectNext(4L)
      .verifyComplete();
}

Обратите внимание, что, как было сказано ранее, этот API гораздо более низкого уровня. Например,instead of dealing with high-level objects, we are sending a stream of bytes, using ByteBuffer. Кроме того, мы используем больше примитивов Redis, таких как SET и SCAN.

Наконец, строковые и ключевые команды - это всего лишь две средиmany command interfaces that Spring Data Redis exposesреактивных команд.

7. Заключение

В этом руководстве мы рассмотрели основы использования шаблона Reactive Redis Spring Data и различные способы его интеграции с нашим приложением.

Полный исходный код примеров доступенover on GitHub.