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

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

Technologies used:

  • 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 for from here.

Unzip the downloaded zip file and start the server by running the redis-server.exe file.

spring boot redis publish subscribe example

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

$ brew update && brew install redis

Redis producer application

We will create a producer application first that produces the message to the Redis server.

Create Spring Boot application

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

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

The spring-boot-starter-data-redis is a starter dependency that provides all the required basic configuration 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>

Create a DTO class

Create a Student.java 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 and support 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.java 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 created a custom Redis serializer that serializes the Student object.
  • We have also 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.

The @Value annotation reads the name of the topic from the application.properties configuration file.

We are using the convertAndSend() method of the RedisTemplate 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);
	}
}

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/ directory.

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

We have 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.

Create Spring Boot consumer application

Create the Spring boot application with the similar dependencies of that of 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>

Create the DTO class

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

We have used the LocalDateDeserializer class to de-serialize the JSON date fields with the date 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: This 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 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.java 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.

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/ directory.

This configuration file contains the Redis server host, port details, which is 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 observe that the message sent successfully to the message broker.

Redis publisher example spring boot

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

Redis publisher spring boot example

We can observe that the consumer has consumed the message and printed the student object.

Redis consumer spring boot

Conclusion

In this article, we learned how to use Redis messaging with Spring Boot. We learned how to create a publish/subscribe application by creating a producer and consumer Spring Boot applications.

Example code is available on GitHub.

You may also be interested in