Eine Einführung in Spring Data Redis Reactive

Eine Einführung in Spring Data Redis Reactive

1. Einführung

In diesem Tutorial werdenwe’re going to learn how to configure and implement Redis operations using Spring Data’s ReactiveRedisTemplate. 

Wir werden die grundlegenden Verwendungen derReactiveRedisTemplate wie das Speichern und Abrufen von Objekten in Redis durchgehen. Und wir werden uns ansehen, wie Redis-Befehle mitReactiveRedisConnectionausgeführt werden.

Um die Grundlagen zu behandeln, lesen Sie unsereIntroduction to Spring Data Redis.

2. Konfiguration

UmReactiveRedisTemplate in unserem Code zu verwenden, müssen wir zuerst das Moduldependency for Spring Boot’s Redis Reactivehinzufügen:


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

3. Aufbau

Dann musswe eine Verbindung mit unserem Redis-Server herstellen. Wir müssen keinen Code für die Konfiguration hinzufügen, wenn Sie mitlocalhost:6379 eine Verbindung zu einem Redis-Server herstellen möchten.

Aberif 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. Operationen auflisten

Redis-Listen sind Listen von Zeichenfolgen, die nach Einfügereihenfolge sortiert sind. Wir können die Elemente der Liste hinzufügen oder entfernen, indem wir sie von links oder rechts schieben oder platzieren.

4.1. String-Vorlage

Um mit Listen arbeiten zu können, benötigen wir eine Instanz vonReactiveRedisTemplate that we’ve provided a String serialization context:

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

Und aus der soeben erstellten String-Vorlage können wir eine Instanz vonReactiveListOperations erhalten:

@Autowired
private ReactiveRedisTemplate redisTemplate;

private ReactiveListOperations reactiveListOps;

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

4.2. LPUSH und LPOP

Nachdem wir nun eine Instanz vonReactiveListOperations, haben, führen wir eine LPUSH-Operation für eine Liste mitdemo_list als Kennung der Liste durch.

Danach führen wir eine LPOP in der Liste durch und überprüfen dann, ob das Element aufgetaucht ist:

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

Beachten Sie, dass wir beim Testen reaktiver KomponentenStepVerifier verwenden können, um den Abschluss der Aufgabe zu blockieren.

5. Wertoperationen

Möglicherweise möchten wir auch benutzerdefinierte Objekte verwenden und nicht nur Strings.

Lassen Sie uns also einige ähnliche Operationen an einemEmployee-Objekt ausführen, um unsere Operationen an einem POJO zu demonstrieren:

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

    // ... getters and setters

    // ... hashCode and equals
}

5.1. Mitarbeitervorlage

Wir müssen eine zweite Instanz vonReactiveRedisTemplate. erstellen. Wir werden weiterhinString  für unseren Schlüssel verwenden, aber diesmal ist der WertEmployee:

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

Um ein benutzerdefiniertes Objekt korrekt zu serialisieren, müssen wir Spring anweisen, wie es gemacht wird. Hier haben wir der Vorlageuse the Jackson library by configuring a Jackson2JsonRedisSerializer for the value mitgeteilt. Da der Schlüssel nur ein String ist, können wir dafürStringRedisSerializer  verwenden.

Wir verwenden dann diesen Serialisierungskontext und unsere Verbindungsfactory, um wie zuvor eine Vorlage zu erstellen.

Als Nächstes erstellen wir eine Instanz vonReactiveValueOperations, wie wir es zuvor mitReactiveListOperations getan haben:

@Autowired
private ReactiveRedisTemplate redisTemplate;

private ReactiveValueOperations reactiveValueOps;

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

5.2. Vorgänge speichern und abrufen

Jetzt, da wir eine Instanz vonReactiveValueOperations, lets haben, können Sie damit eine Instanz vonEmployee speichern:

@Test
public void givenEmployee_whenSet_thenSet() {

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

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

Und dann können wir das gleiche Objekt von Redis zurückbekommen:

@Test
public void givenEmployeeId_whenGet_thenReturnsEmployee() {

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

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

5.3. Operationen mit Ablaufzeit

Wir wollen oftput values in a cache that will naturally expire, und wir können dies mit der gleichenset operation tun:

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

Beachten Sie, dass dieser Test einige seiner eigenen Blockierungen vornimmt, um auf das Ablaufen des Cache-Schlüssels zu warten.

6. Redis-Befehle

Redis-Befehle sind im Grunde genommen Methoden, die ein Redis-Client auf einem Server aufrufen kann. Und Redis unterstützt Dutzende von Befehlen, von denen wir einige bereits gesehen haben, wie LPUSH und LPOP.

DieOperations API ist eine übergeordnete Abstraktion um Redis 'Befehlssatz.

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

Schauen wir uns also die Befehle String und Key durch die Linse derCommands-API an.

6.1. Zeichenfolgen- und Schlüsselbefehle

Um Redis-Befehlsoperationen auszuführen, erhalten wir Instanzen vonReactiveKeyCommands undReactiveStringCommands.

Wir können beide von unsererReactiveRedisConnectionFactory-Instanz erhalten:

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

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

6.2. Operationen einstellen und abrufen

Wir könnenReactiveStringCommands verwenden, um mehrere Schlüssel mit einem einzigen Aufruf zu speichern,basically invoking the SET command multiple times.

Und dann können wir diese Schlüssel überReactiveKeyCommands,invoking the KEYS command abrufen:

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

Beachten Sie, dass diese API, wie bereits erwähnt, viel niedriger ist. Zum Beispielinstead of dealing with high-level objects, we are sending a stream of bytes, using ByteBuffer. Wir verwenden auch mehr der Redis-Primitive wie SET und SCAN.

Schließlich sind String- und Schlüsselbefehle nur zwei untermany command interfaces that Spring Data Redis exposes reaktiv.

7. Fazit

In diesem Tutorial haben wir die Grundlagen der Verwendung der reaktiven Redis-Vorlage von Spring Data und die verschiedenen Möglichkeiten zur Integration in unsere Anwendung behandelt.

Der vollständige Quellcode für die Beispiele istover on GitHub verfügbar.