Une introduction à Spring Data Redis Reactive

Une introduction à Spring Data Redis Reactive

1. introduction

Dans ce didacticiel,we’re going to learn how to configure and implement Redis operations using Spring Data’s ReactiveRedisTemplate. 

Nous allons passer en revue les utilisations de base desReactiveRedisTemplate, comme la façon de stocker et de récupérer des objets dans Redis. Et nous allons voir comment exécuter les commandes Redis à l'aide desReactiveRedisConnection.

Pour couvrir les bases, consultez nosIntroduction to Spring Data Redis.

2. Installer

Pour utiliserReactiveRedisTemplate in notre code, nous devons d'abord ajouter le moduledependency for Spring Boot’s Redis Reactive:


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

3. Configuration

Ensuite,we doit établir une connexion avec notre serveur Redis. Nous n'avons pas besoin d'ajouter de code pour la configuration si vous souhaitez vous connecter à un serveur Redis àlocalhost:6379.

Mais,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. Opérations de liste

Les listes Redis sont des listes de chaînes triées par ordre d'insertion. Nous pouvons ajouter ou supprimer des éléments de la liste en les poussant ou en les faisant apparaître à gauche ou à droite.

4.1. Modèle de chaîne

Pour travailler avec les listes, nous aurons besoin d'une instance deReactiveRedisTemplate that we’ve provided a String serialization context:

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

Et à partir du modèle String que nous venons de créer, nous pouvons obtenir une instance deReactiveListOperations:

@Autowired
private ReactiveRedisTemplate redisTemplate;

private ReactiveListOperations reactiveListOps;

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

4.2. LPUSH et LPOP

Maintenant que nous avons une instance deReactiveListOperations,, faisons une opération LPUSH pour une liste avecdemo_list comme identifiant de la liste.

Après cela, nous ferons un LPOP sur la liste, puis vérifierons l'élément apparu:

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

Notez que lors du test de composants réactifs, nous pouvons utiliserStepVerifier pour bloquer l'achèvement de la tâche.

5. Opérations de valeur

Nous voudrons peut-être aussi utiliser des objets personnalisés, et pas seulement des chaînes.

Alors, faisons quelques opérations similaires sur un objetEmployee pour démontrer nos opérations sur un POJO:

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

    // ... getters and setters

    // ... hashCode and equals
}

5.1. Modèle d'employé

Nous devrons créer une deuxième instance deReactiveRedisTemplate. Nous utiliserons toujoursString  pour notre clé, mais cette fois la valeur seraEmployee:

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

Afin de sérialiser correctement un objet personnalisé, nous devons indiquer à Spring comment le faire. Ici, nous avons indiqué le modèle àuse the Jackson library by configuring a Jackson2JsonRedisSerializer for the value. Puisque la clé n'est qu'une chaîne, nous pouvons utiliser leStringRedisSerializer  pour cela.

Nous utilisons ensuite ce contexte de sérialisation et notre fabrique de connexions pour créer un modèle comme auparavant.

Ensuite, nous allons créer une instance deReactiveValueOperations comme nous l'avons fait précédemment avecReactiveListOperations:

@Autowired
private ReactiveRedisTemplate redisTemplate;

private ReactiveValueOperations reactiveValueOps;

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

5.2. Enregistrer et récupérer des opérations

Maintenant que nous avons une instance deReactiveValueOperations, let, utilisez-la pour stocker une instance deEmployee:

@Test
public void givenEmployee_whenSet_thenSet() {

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

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

Et puis nous pouvons récupérer le même objet de Redis:

@Test
public void givenEmployeeId_whenGet_thenReturnsEmployee() {

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

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

5.3. Opérations avec heure d'expiration

Nous voulons souventput values in a cache that will naturally expire, et nous pouvons le faire avec la même opérationset :

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

Notez que ce test effectue son propre blocage en attendant l'expiration de la clé de cache.

6. Commandes Redis

Les commandes Redis sont essentiellement des méthodes qu'un client Redis peut invoquer sur un serveur. Et Redis supporte des dizaines de commandes, dont certaines que nous avons déjà vues, comme LPUSH et LPOP.

LeOperations API est une abstraction de plus haut niveau autour de l'ensemble de commandes de Redis.

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

Jetons donc un œil aux commandes String et Key à travers l'objectif de l'APICommands.

6.1. Commandes de chaîne et touches

Pour effectuer les opérations de commande Redis, nous obtiendrons des instances deReactiveKeyCommands etReactiveStringCommands.

Nous pouvons les obtenir tous les deux à partir de notre instanceReactiveRedisConnectionFactory:

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

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

6.2. Définir et obtenir des opérations

Nous pouvons utiliserReactiveStringCommands pour stocker plusieurs clés avec un seul appel,basically invoking the SET command multiple times.

Et puis, nous pouvons récupérer ces clés viaReactiveKeyCommands,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();
}

Notez que, comme indiqué précédemment, cette API est beaucoup plus basse. Par exemple,instead of dealing with high-level objects, we are sending a stream of bytes, using ByteBuffer. En outre, nous utilisons davantage de primitives Redis telles que SET et SCAN.

Enfin, les commandes de chaînes et de touches ne sont que deux parmi lesmany command interfaces that Spring Data Redis exposes de manière réactive.

7. Conclusion

Dans ce didacticiel, nous avons abordé les bases de l'utilisation du modèle Reactive Redis de Spring Data et les différentes façons dont nous pouvons l'intégrer à notre application.

Le code source complet des exemples est disponibleover on GitHub.