Spring Data Redis
Spring Data Redis provides a reactive variant of RedisConnectionFactory
aka ReactiveRedisConnectionFactory
which return a ReactiveConnection
.
Getting Started
Follow the the Getting Started part to create a freestyle or Spring Boot based project skeleton.
For none Spring Boot project, add the following dependencies to the pom.xml.
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
NOTE: You have to use
lettuce
as Redis driver to get reactive support inspring-data-redis
, and addcommons-pool2
to support Redis connection pool.
Create a @Configuration
class to configure Mongo and enable Reactive support for Redis.
@Configuration
@Slf4j
public class RedisConfig {
@Bean
public ReactiveRedisConnectionFactory connectionFactory() {
return new LettuceConnectionFactory("localhost", 6379);
}
// @Bean
// public ReactiveRedisConnectionFactory lettuceConnectionFactory() {
//
// LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
// .useSsl().and()
// .commandTimeout(Duration.ofSeconds(2))
// .shutdownTimeout(Duration.ZERO)
// .build();
//
// return new LettuceConnectionFactory(new RedisStandaloneConfiguration("localhost", 6379), clientConfig);
// }
@Bean
public ReactiveRedisTemplate<String, Post> reactiveRedisTemplate(ReactiveRedisConnectionFactory factory) {
return new ReactiveRedisTemplate<String, Post>(
factory,
RedisSerializationContext.fromSerializer(new Jackson2JsonRedisSerializer(Post.class))
);
}
}
LettuceConnectionFactory
implements RedisConnectionFactory
and ReactiveRedisConnectionFactory
interfaces, when a LettuceConnectionFactory
is declared, both RedisConnectionFactory
and ReactiveRedisConnectionFactory
are registered as Spring beans.
In your components, you can inject a ReactiveRedisConnectionFactory
bean to get a ReactiveConnection1
.
@Inject ReactiveRedisConnectionFactory factory;
ReactiveRedisConnection conn = factory.getReactiveConnection();
ReactiveConnection
provides some reactive methods for Redis operations.
For example, create a favorites list for posts.
conn.setCommands()
.sAdd(
ByteBuffer.wrap("users:user:favorites".getBytes()),
this.posts.findAll()
.stream()
.map(p -> p.getId().getBytes())
.map(ByteBuffer::wrap)
.collect(Collectors.toList())
)
.log()
.subscribe(null, null, ()-> log.info("added favirates..."));
And show my favorites in the controller.
@RestController()
@RequestMapping(value = "/favorites")
class FavoriteController {
private final ReactiveRedisConnectionFactory factory;
public FavoriteController(ReactiveRedisConnectionFactory factory) {
this.factory = factory;
}
@GetMapping("")
public Mono<List<String>> all() {
return this.factory.getReactiveConnection()
.setCommands()
.sMembers(ByteBuffer.wrap("users:user:favorites".getBytes()))
.map(FavoriteController::toString)
.collectList();
}
private static String toString(ByteBuffer byteBuffer) {
byte[] bytes = new byte[byteBuffer.remaining()];
byteBuffer.get(bytes);
return new String(bytes);
}
}
For the complete codes, check spring-reactive-sample/data-redis.
For Spring Boot applications, the configuration can be simplified. Just add spring-boot-starter-data-redis-reactive
into the project dependencies.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
Spring boot provides auto-configuration for Redis, and registers ReactiveRedisConnectionFactory
for you automatically.
For the complete codes, check spring-reactive-sample/boot-data-redis.
ReactiveRedisTemplate
Beside the ReactiveRedisConnectionFactory
, Spring Data Redis also provides a variant for RedisTemplate
.
Let's try to add some sample via a generic Repository interface. Create a Post
class to present a Redis hash data, add @RedisHash("posts")
to Post
class.
@Data
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
@RedisHash("posts")
class Post {
@Id
private String id;
private String title;
private String content;
}
Create a PostRepository
and use ReactiveRedisOperations
to access the Redis database.
@Repository
@RequiredArgsConstructor
class PostRepository {
private final ReactiveRedisOperations<String, Post> reactiveRedisOperations;
public Flux<Post> findAll(){
return this.reactiveRedisOperations.opsForList().range("posts", 0, -1);
}
public Mono<Post> findById(String id) {
return this.findAll().filter(p -> p.getId().equals(id)).last();
}
public Mono<Long> save(Post post){
return this.reactiveRedisOperations.opsForList().rightPush("posts", post);
}
public Mono<Boolean> deleteAll() {
return this.reactiveRedisOperations.opsForList().delete("posts");
}
}
Redis Messaging
Redis is well known as a key value database, it is also famous for a light-weight messaging broker.
Declare a ReactiveRedisMessageListenerContainer
bean to receive messaging from Redis.
@Bean
public ReactiveRedisMessageListenerContainer redisMessageListenerContainer(PostRepository posts, ReactiveRedisConnectionFactory connectionFactory) {
ReactiveRedisMessageListenerContainer container = new ReactiveRedisMessageListenerContainer(connectionFactory);
ObjectMapper objectMapper = new ObjectMapper();
container.receive(ChannelTopic.of("posts"))
.map(p->p.getMessage())
.map(m -> {
try {
Post post= objectMapper.readValue(m, Post.class);
post.setId(UUID.randomUUID().toString());
return post;
} catch (IOException e) {
return null;
}
})
.switchIfEmpty(Mono.error(new IllegalArgumentException()))
.flatMap(p-> posts.save(p))
.subscribe(c-> log.info(" count:" + c), null , () -> log.info("saving post."));
return container;
}
Send a message using ReactiveRedisOperations
bean.
@RestController()
@RequestMapping(value = "/posts")
@RequiredArgsConstructor
class PostController {
//...
@PostMapping("")
public Mono<Long> save(@RequestBody Post post) {
return this.reactiveRedisOperations.convertAndSend("posts", post );
}
}
For the complete codes, check spring-reactive-sample/data-redis-message.