Uma Introdução aos Dados Spring Redis Reativo

Uma Introdução aos Dados Spring Redis Reativo

1. Introdução

Neste tutorial,we’re going to learn how to configure and implement Redis operations using Spring Data’s ReactiveRedisTemplate. 

Veremos os usos básicos doReactiveRedisTemplate, como armazenar e recuperar objetos no Redis. E vamos dar uma olhada em como executar comandos do Redis usandoReactiveRedisConnection.

Para cobrir o básico, verifique nossoIntroduction to Spring Data Redis.

2. Configuração

Para usarReactiveRedisTemplate em nosso código, primeiro, precisamos adicionar o módulodependency for Spring Boot’s Redis Reactive:


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

3. Configuração

Então,we precisa estabelecer uma conexão com nosso servidor Redis. Não precisamos adicionar nenhum código para configuração se quisermos nos conectar a um servidor Redis emlocalhost:6379.

Mas,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. Operações de lista

Listas Redis são listas de Strings classificadas por ordem de inserção. Podemos adicionar ou remover os elementos da lista pressionando-os ou movendo-os da esquerda ou da direita.

4.1. Modelo de String

Para trabalhar com listas, precisaremos de uma instância deReactiveRedisTemplate that we’ve provided a String serialization context:

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

E a partir do modelo String que acabamos de criar, podemos obter uma instância deReactiveListOperations:

@Autowired
private ReactiveRedisTemplate redisTemplate;

private ReactiveListOperations reactiveListOps;

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

4.2. LPUSH e LPOP

Agora que temos uma instância deReactiveListOperations,, vamos fazer uma operação LPUSH para uma lista comdemo_list como o identificador da lista.

Depois disso, faremos um LPOP na lista e, em seguida, verificaremos o elemento exibido:

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

Observe que ao testar componentes reativos, podemos usarStepVerifier para bloquear a conclusão da tarefa.

5. Operações de valor

Também podemos usar objetos personalizados, e não apenas Strings.

Então, vamos fazer algumas operações semelhantes em um objetoEmployee para demonstrar nossas operações em um POJO:

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

    // ... getters and setters

    // ... hashCode and equals
}

5.1. Modelo de funcionário

Precisaremos criar uma segunda instância deReactiveRedisTemplate.. Ainda usaremosString  para nossa chave, mas desta vez o valor será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);
}

Para serializar corretamente um objeto personalizado, precisamos instruir o Spring sobre como fazê-lo. Aqui, informamos o modelo parause the Jackson library by configuring a Jackson2JsonRedisSerializer for the value. Como a chave é apenas uma string, podemos usarStringRedisSerializer  para isso.

Em seguida, levamos esse contexto de serialização e nossa fábrica de conexões para criar um modelo como antes.

A seguir, criaremos uma instância deReactiveValueOperations exatamente como fizemos anteriormente comReactiveListOperations:

@Autowired
private ReactiveRedisTemplate redisTemplate;

private ReactiveValueOperations reactiveValueOps;

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

5.2. Salvar e recuperar operações

Agora que temos uma instância deReactiveValueOperations, let's, use-a para armazenar uma instância deEmployee:

@Test
public void givenEmployee_whenSet_thenSet() {

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

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

E então podemos recuperar o mesmo objeto do Redis:

@Test
public void givenEmployeeId_whenGet_thenReturnsEmployee() {

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

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

5.3. Operações com Tempo de Expiração

Freqüentemente, queremosput values in a cache that will naturally expire, e podemos fazer isso com a mesma operaçãoset :

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

Observe que esse teste executa alguns de seus próprios bloqueios para aguardar a expiração da chave de cache.

6. Comandos Redis

Os comandos Redis são basicamente métodos que um cliente Redis pode chamar em um servidor. E o Redis suporta dezenas de comandos, alguns dos quais já vimos, como LPUSH e LPOP.

OOperations API é uma abstração de nível superior em torno do conjunto de comandos do Redis.

No entanto,if we want to use the Redis command primitives more directly, then Spring Data Redis Reactive also gives us a Commands API.

Então, vamos dar uma olhada nos comandos String e Key através da lente da APICommands.

6.1. Comandos de string e chave

Para realizar as operações de comando do Redis, obteremos instâncias deReactiveKeyCommands eReactiveStringCommands.

Podemos obtê-los em nossa instânciaReactiveRedisConnectionFactory:

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

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

6.2. Definir e obter operações

Podemos usarReactiveStringCommands para armazenar várias chaves com uma única chamada,basically invoking the SET command multiple times.

E então, podemos recuperar essas chaves por meio deReactiveKeyCommands,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();
}

Observe que, conforme declarado anteriormente, essa API é muito mais de baixo nível. Por exemplo,instead of dealing with high-level objects, we are sending a stream of bytes, using ByteBuffer. Além disso, usamos mais das primitivas Redis como SET e SCAN.

Finalmente, String e Key Commands são apenas dois entremany command interfaces that Spring Data Redis exposes reativamente.

7. Conclusão

Neste tutorial, cobrimos os fundamentos do uso do modelo reativo Redis do Spring Data e as várias maneiras pelas quais podemos integrá-lo ao nosso aplicativo.

O código-fonte completo dos exemplos está disponívelover on GitHub.