Skip to content

Commit c285805

Browse files
committed
spring-projects#323 - Add examples for Reactive Redis Template.
1 parent bd7b5e5 commit c285805

File tree

5 files changed

+200
-2
lines changed

5 files changed

+200
-2
lines changed

redis/reactive/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@
2929
<artifactId>lettuce-core</artifactId>
3030
</dependency>
3131

32+
<dependency>
33+
<groupId>io.projectreactor</groupId>
34+
<artifactId>reactor-test</artifactId>
35+
<scope>test</scope>
36+
</dependency>
37+
3238
<dependency>
3339
<groupId>${project.groupId}</groupId>
3440
<artifactId>spring-data-redis-example-utils</artifactId>

redis/reactive/src/test/java/example/springdata/redis/RedisTestConfiguration.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016 the original author or authors.
2+
* Copyright 2016-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -20,8 +20,11 @@
2020
import org.springframework.beans.factory.annotation.Autowired;
2121
import org.springframework.boot.autoconfigure.SpringBootApplication;
2222
import org.springframework.context.annotation.Bean;
23+
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
2324
import org.springframework.data.redis.connection.RedisConnectionFactory;
2425
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
26+
import org.springframework.data.redis.core.ReactiveRedisTemplate;
27+
import org.springframework.data.redis.serializer.RedisSerializationContext;
2528

2629
/**
2730
* @author Mark Paluch
@@ -32,10 +35,15 @@ public class RedisTestConfiguration {
3235
@Autowired RedisConnectionFactory factory;
3336

3437
@Bean
35-
public RedisConnectionFactory redisConnectionFactory() {
38+
public LettuceConnectionFactory redisConnectionFactory() {
3639
return new LettuceConnectionFactory();
3740
}
3841

42+
@Bean
43+
public ReactiveRedisTemplate<String, String> reactiveRedisTemplate(ReactiveRedisConnectionFactory connectionFactory) {
44+
return new ReactiveRedisTemplate<>(connectionFactory, RedisSerializationContext.string());
45+
}
46+
3947
/**
4048
* Clear database before shut down.
4149
*/
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Copyright 2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package example.springdata.redis.operations;
17+
18+
import example.springdata.redis.RedisTestConfiguration;
19+
import example.springdata.redis.test.util.RequiresRedisServer;
20+
import lombok.extern.slf4j.Slf4j;
21+
import reactor.core.publisher.Mono;
22+
import reactor.test.StepVerifier;
23+
24+
import java.time.Duration;
25+
import java.util.logging.Level;
26+
27+
import org.junit.Before;
28+
import org.junit.ClassRule;
29+
import org.junit.Test;
30+
import org.junit.runner.RunWith;
31+
import org.springframework.beans.factory.annotation.Autowired;
32+
import org.springframework.boot.test.context.SpringBootTest;
33+
import org.springframework.data.redis.core.ReactiveListOperations;
34+
import org.springframework.data.redis.core.ReactiveRedisOperations;
35+
import org.springframework.test.context.junit4.SpringRunner;
36+
37+
/**
38+
* Show usage of reactive Template API on Redis lists using {@link ReactiveRedisOperations}.
39+
*
40+
* @author Mark Paluch
41+
*/
42+
@Slf4j
43+
@RunWith(SpringRunner.class)
44+
@SpringBootTest(classes = RedisTestConfiguration.class)
45+
public class ListOperationsTests {
46+
47+
// we only want to run this tests when redis is up an running
48+
public static @ClassRule RequiresRedisServer requiresServer = RequiresRedisServer.onLocalhost();
49+
50+
@Autowired ReactiveRedisOperations<String, String> operations;
51+
52+
@Before
53+
public void before() {
54+
StepVerifier.create(operations.execute(it -> it.serverCommands().flushDb())).expectNext("OK").verifyComplete();
55+
}
56+
57+
/**
58+
* A simple queue using Redis blocking list commands {@code BLPOP} and {@code LPUSH} to produce the queue message.
59+
*/
60+
@Test
61+
public void shouldPollAndPopulateQueue() {
62+
63+
String queue = "foo";
64+
65+
ReactiveListOperations<String, String> listOperations = operations.opsForList();
66+
67+
Mono<String> blpop = listOperations //
68+
.leftPop(queue, Duration.ofSeconds(30)) //
69+
.log("example.springdata.redis", Level.INFO);
70+
71+
log.info("Blocking pop...waiting for message");
72+
StepVerifier.create(blpop) //
73+
.then(() -> {
74+
75+
Mono.delay(Duration.ofSeconds(10)).doOnSuccess(it -> {
76+
77+
log.info("Subscriber produces message");
78+
79+
}).then(listOperations.leftPush(queue, "Hello, World!")).subscribe();
80+
81+
}).expectNext("Hello, World!").verifyComplete();
82+
83+
log.info("Blocking pop...done!");
84+
}
85+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Copyright 2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package example.springdata.redis.operations;
17+
18+
import static org.assertj.core.api.Assertions.*;
19+
20+
import example.springdata.redis.RedisTestConfiguration;
21+
import example.springdata.redis.test.util.RequiresRedisServer;
22+
import lombok.extern.slf4j.Slf4j;
23+
import reactor.core.publisher.Mono;
24+
import reactor.test.StepVerifier;
25+
26+
import java.time.Duration;
27+
28+
import org.junit.Before;
29+
import org.junit.ClassRule;
30+
import org.junit.Test;
31+
import org.junit.runner.RunWith;
32+
import org.springframework.beans.factory.annotation.Autowired;
33+
import org.springframework.boot.test.context.SpringBootTest;
34+
import org.springframework.data.redis.core.ReactiveRedisOperations;
35+
import org.springframework.data.redis.core.ReactiveValueOperations;
36+
import org.springframework.test.context.junit4.SpringRunner;
37+
38+
/**
39+
* Show usage of reactive Template API on Redis strings using {@link ReactiveRedisOperations}.
40+
*
41+
* @author Mark Paluch
42+
*/
43+
@Slf4j
44+
@RunWith(SpringRunner.class)
45+
@SpringBootTest(classes = RedisTestConfiguration.class)
46+
public class ValueOperationsTests {
47+
48+
// we only want to run this tests when redis is up an running
49+
public static @ClassRule RequiresRedisServer requiresServer = RequiresRedisServer.onLocalhost();
50+
51+
@Autowired ReactiveRedisOperations<String, String> operations;
52+
53+
@Before
54+
public void before() {
55+
StepVerifier.create(operations.execute(it -> it.serverCommands().flushDb())).expectNext("OK").verifyComplete();
56+
}
57+
58+
/**
59+
* Implement a simple caching sequence using {@code GET} and {@code SETEX} commands.
60+
*/
61+
@Test
62+
public void shouldCacheValue() {
63+
64+
String cacheKey = "foo";
65+
66+
ReactiveValueOperations<String, String> valueOperations = operations.opsForValue();
67+
68+
Mono<String> cachedMono = valueOperations.get(cacheKey) //
69+
.switchIfEmpty(cacheValue().flatMap(it -> {
70+
71+
return valueOperations.set(cacheKey, it, Duration.ofSeconds(60)).then(Mono.just(it));
72+
}));
73+
74+
log.info("Initial access (takes a while...)");
75+
76+
StepVerifier.create(cachedMono).expectSubscription() //
77+
.expectNoEvent(Duration.ofSeconds(9)) //
78+
.expectNext("Hello, World!") //
79+
.verifyComplete();
80+
81+
log.info("Subsequent access (use cached value)");
82+
83+
Duration duration = StepVerifier.create(cachedMono) //
84+
.expectNext("Hello, World!") //
85+
.verifyComplete();
86+
87+
log.info("Done");
88+
89+
assertThat(duration).isLessThan(Duration.ofSeconds(2));
90+
}
91+
92+
/**
93+
* @return the cache value that is expensive to calculate.
94+
*/
95+
private Mono<String> cacheValue() {
96+
return Mono.delay(Duration.ofSeconds(10)).then(Mono.just("Hello, World!"));
97+
}
98+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
logging.level.root=WARN
2+
logging.level.example.springdata.redis=INFO

0 commit comments

Comments
 (0)