Redis Messaging Example With Spring Boot

In the previous article, we learned how to use the Redis key-value store as a NoSQL database. In this article, we will learn how to use the Redis store as a messaging broker with Spring Boot.

We will create producer and consumer applications. We will also learn how to publish the message to the Redis server and listen to the message from the consumer application.

Version details:

  • Spring Boot version: 2.3.1.RELEASE
  • Java version 1.8
  • Redis for windows version: 3.2.100

Installing Redis

If we are using the Windows system, we can download the slightly outdated Redis server in the zip from here.

Now, unzip the downloaded zip file, and start the server by running the redis-server executable file.

spring boot redis publish subscribe example

If you are using Mac OS X/Linux, you can use brew and execute the following command in the terminal.

$ brew update && brew install redis

Redis producer application

Let us create a producer application first that produces the message to the Redis server.

Creating the Spring Boot application

Create a Spring boot application and add the below dependencies in the pom file.

We are using spring data redis, web starter dependencies, and also Lombok dependencies in our application.

Also, the spring boot data redis starter dependency provides all the required basic configurations for our Spring Boot application to interact with the Redis server.

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
	<optional>true</optional>
</dependency>

Creating a DTO class

Create a Student DTO class.

We will pass this student object to the Redis messaging broker.

package com.asbnotebook.dto;
import java.time.LocalDate;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class Student {
	private Integer id;
	private String name;
	@JsonSerialize(using = LocalDateSerializer.class)
	@JsonFormat(pattern = "dd/MM/yyyy") 
	private LocalDate dob;
}

We have used the LocalDateSerializer class to serialize the input date JSON fields. The date field supports the format dd/MM/yyyy.

Configure Redis producer

Spring Boot provides the default configuration required for the Redis messaging that is sufficient for the messaging.

We will create a configuration class and learn how to customize the default configuration.

Create a RedisProducerConfig class, as shown below.

package com.asbnotebook.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import com.asbnotebook.dto.Student;
@Configuration
public class RedisProducerConfig {
	@Bean
	RedisTemplate<String, Student> redisTemplate(RedisConnectionFactory connectionFactory,
			Jackson2JsonRedisSerializer<Student> serializer) {
		RedisTemplate<String, Student> redisTemplate = new RedisTemplate<>();
		redisTemplate.setConnectionFactory(connectionFactory);
		redisTemplate.setDefaultSerializer(serializer);
		redisTemplate.afterPropertiesSet();
		return redisTemplate;
	}
	@Bean
	public Jackson2JsonRedisSerializer<Student> jackson2JsonRedisSerializer() {
		return new Jackson2JsonRedisSerializer<>(Student.class);
	}
}

Important things to notice here are:

  • @Configuration: Indicates that this is a Spring configuration class.
  • Jackson2JsonRedisSerializer: We have also created a custom Redis serializer that serializes the Student object.
  • Finally, we have customized the RedisTemplate bean by configuring it with the custom Redis serializer to support the Student object as a message body.

Sending the message to Redis server

We will create a utility class that will have a utility method that uses our custom Redis template to send the Student object to the Redis server.

We are also using the @Value annotation to read the name of the topic from the application.properties configuration file.

Finally, we are using the convertAndSend method of the Redis Template to publish the message to the Redis message broker.

package com.asbnotebook.apiagent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import com.asbnotebook.dto.Student;
@Component
public class StudentProducer {
	@Autowired
	private RedisTemplate<String, Student> redisTemplate;
	@Value("${redis.student.topic}")
	private String messageTopic;
	public void sendMessage(Student student) {
		System.out.println("Sending Student details: " + student);
		redisTemplate.convertAndSend(messageTopic, student);
	}
}

Create a REST controller with a POST endpoint.

We will send the JSON request object to this endpoint that will be published to the Redis message broker using the utility class we have created earlier.

package com.asbnotebook.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.asbnotebook.apiagent.StudentProducer;
import com.asbnotebook.dto.Student;
@RestController
public class StudentController {
	@Autowired
	private StudentProducer studentProducer;
	@PostMapping("/send-message")
	public ResponseEntity<String> sendMessage(@RequestBody Student student) {
		studentProducer.sendMessage(student);
		return new ResponseEntity<>("Message sent successfully", HttpStatus.OK);
	}
}

Finally, the endpoint will display a successful string message after sending the message to the Redis broker.

Add the Redis configuration properties

Add the below configuration properties to the producer application’s application.properties file under the /src/main/resources/ folder.

spring.redis.host=localhost
spring.redis.port=6379
redis.student.topic=studentTopic

We have also specified the Redis configurations by setting the Redis server host, port, and the message topic.

Redis consumer application

Create a consumer application by creating a new Spring boot application. This application will consume the messages from the Redis server that have been published earlier by the producer application.

Creating the Spring Boot consumer application

Create the Spring boot application with similar dependencies to that of the producer application.

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
	<optional>true</optional>
</dependency>

Creating the DTO class

Create the Student DTO class, similar to that of the producer application.

We have used the LocalDateDeserializer class to de-serialize the JSON date field.

Also, the date is deserialized with the format: dd/MM/yyyy.

package com.asbnotebook.dto;
import java.time.LocalDate;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class Student {
	private Integer id;
	private String name;
	@JsonDeserialize(using = LocalDateDeserializer.class)
	@JsonFormat(pattern = "dd/MM/yyyy")
	private LocalDate dob;
}

Configure Redis consumer

Create a Redis consumer configuration class to customize the consumer configurations.

package com.asbnotebook.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import com.asbnotebook.apiagent.StudentConsumer;
import com.asbnotebook.dto.Student;
@Configuration
public class RedisListenerConfig {
	@Value("${redis.student.topic}")
	private String studentTopic;
	@Bean
	public RedisMessageListenerContainer listenerContainer(MessageListenerAdapter listenerAdapter,
			RedisConnectionFactory connectionFactory) {
		RedisMessageListenerContainer container = new RedisMessageListenerContainer();
		container.setConnectionFactory(connectionFactory);
		container.addMessageListener(listenerAdapter, new PatternTopic(studentTopic));
		return container;
	}
	@Bean
	public MessageListenerAdapter listenerAdapter(StudentConsumer consumer) {
		MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter(consumer);
		messageListenerAdapter.setSerializer(new Jackson2JsonRedisSerializer<>(Student.class));
		return messageListenerAdapter;
	}
	@Bean
	RedisTemplate<String, Student> redisTemplate(RedisConnectionFactory connectionFactory,
			Jackson2JsonRedisSerializer<Student> serializer) {
		RedisTemplate<String, Student> redisTemplate = new RedisTemplate<>();
		redisTemplate.setConnectionFactory(connectionFactory);
		redisTemplate.setDefaultSerializer(serializer);
		redisTemplate.afterPropertiesSet();
		return redisTemplate;
	}
	@Bean
	public Jackson2JsonRedisSerializer<Student> jackson2JsonRedisSerializer() {
		return new Jackson2JsonRedisSerializer<>(Student.class);
	}
}

Important points to notice here are:

  • RedisMessageListenerContainer: The bean is helpful to configure the Redis topic that the consumer application should consume.
  • MessageListenerAdapter: This bean is configured with the custom Jackson2JsonRedisSerializer serializer. This class also expects us to define a handleMethod() that consumes the Redis message.
  • We also have created a custom Jackson2JsonRedisSerializer bean to support the student object. This bean configuration is similar to that of the producer application.
  • We have also created a custom RedisTemplate Bean.

Consuming the message from Redis

Create a StudentConsumer component class. This class will be our Redis consumer class.

By default, we have to create a method with the name handleMessage. This method will listen to the topics that are specified in the configuration.

Also, the method parameter should contain the object type that it consumes. In our example, the method accepts the Student object.

package com.asbnotebook.apiagent;
import org.springframework.stereotype.Component;
import com.asbnotebook.dto.Student;
@Component
public class StudentConsumer {
	public void handleMessage(Student student) {
		System.out.println("Consumer> " + student);
	}
}

Adding the Redis consumer configuration properties

Add the below configuration properties to the application.properties file under the /src/main/resources/ folder.

The configuration file contains the Redis server host, port details, which are similar to that of the producer application.

The configured topic here is the topic name that is used by the producer application while publishing the message.

spring.redis.host=localhost
spring.redis.port=6379
redis.student.topic=studentTopic
server.port=8081

We have also updated the server port(8081) of the consumer application to avoid any conflict with the producer application.

Testing the application

Start the Spring Boot producer and consumer applications.

Send the student details by sending the proper JSON request to the /send-message POST endpoint.

Redis publisher spring boot

We can also observe that the message was sent successfully to the message broker.

Redis publisher example spring boot

We can also observe published messages to the studentTopic on the Redis server.

Redis publisher spring boot example

Finally, the consumer consumes the message and prints the student object as shown below.

Redis consumer spring boot

Conclusion

In this article, we learned how to use Redis messaging with Spring Boot.

We also learned how to create a publish/subscribe application by creating producer and consumer Spring Boot applications.

Finally, the example code is available on GitHub.