Spring Boot uses Redis to publish and subscribe messages

brief introduction

Today, the senior students will teach you how to use Spring Data's support for Redis to realize the publish and subscribe mechanism of messages. Publish and subscribe is a typical asynchronous communication model, which can fully decouple the publisher and subscriber of messages. In our example, we will use StringRedisTemplate to publish a string message, and use a POJO based on messagelistener adapter to subscribe to and respond to messages.

Tips

In fact, RedisRedis not only provides a NoSQL database, but also provides a message system.

Environmental preparation

Development environment:

  • IDE+Java environment (JDK 1.7 or above)
  • Maven 3.0 + (Eclipse and Idea IntelliJ are built-in. If you use IDE and do not use command-line tools, you can not install it)

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.tianmaing</groupId>
  <artifactId>redis-message</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>redis-message</name>
  <description>Demo of message processing by redis</description>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.2.5.RELEASE</version>
    <relativePath/>
  </parent>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>  
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-redis</artifactId>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>

</project>

By configuring the Spring Boot starter Redis dependency, the Spring Boot support for Redis is introduced.

Create the recipient of Redis message

In any message based application, there are message publishers and message receivers (or called message subscribers). To create a message receiver, we only need a common POJO and define a message receiving method in the POJO:

package com.tianmaying.springboot.redisdemo;

import java.util.concurrent.CountDownLatch;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

public class Receiver {
    private static final Logger LOGGER = LoggerFactory.getLogger(Receiver.class);

    private CountDownLatch latch;

    @Autowired
    public Receiver(CountDownLatch latch) {
        this.latch = latch;
    }

    public void receiveMessage(String message) {
        LOGGER.info("Received <" + message + ">");
        latch.countDown();
    }
}

When the Receiver class will be registered as a message listener. The method of processing messages can be named arbitrarily, and we have considerable flexibility.

We inject a CountDownLatch instance into the constructor of the Receiver through the @ AutoWired annotation. When a message is received, we call the cutDown() method.

Register listeners and send messages

Spring Data Redis provides all required components for sending and receiving messages based on Redis. We only need to configure three things:

  • A connection factory
  • A message listener container
  • A Redis template

We will send messages through the Redis template and register the Receiver with the message listener container. The connection factory connects the two so that they can communicate through the Redis server. How to connect? We can inject the connection factory instance into the listener container and Redis template respectively.

package com.tianmaying.springboot.redisdemo;

import java.util.concurrent.CountDownLatch;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;

@SpringBootApplication
public class App {

    private static final Logger LOGGER = LoggerFactory.getLogger(App.class);

    @Bean
    RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
            MessageListenerAdapter listenerAdapter) {

        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        container.addMessageListener(listenerAdapter, new PatternTopic("chat"));

        return container;
    }

    @Bean
    MessageListenerAdapter listenerAdapter(Receiver receiver) {
        return new MessageListenerAdapter(receiver, "receiveMessage");
    }

    @Bean
    Receiver receiver(CountDownLatch latch) {
        return new Receiver(latch);
    }

    @Bean
    CountDownLatch latch() {
        return new CountDownLatch(1);
    }

    @Bean
    StringRedisTemplate template(RedisConnectionFactory connectionFactory) {
        return new StringRedisTemplate(connectionFactory);
    }

    public static void main(String[] args) throws InterruptedException {

        ApplicationContext ctx = SpringApplication.run(App.class, args);

        StringRedisTemplate template = ctx.getBean(StringRedisTemplate.class);
        CountDownLatch latch = ctx.getBean(CountDownLatch.class);

        LOGGER.info("Sending message...");
        template.convertAndSend("chat", "Hello from Redis!");

        latch.await();

        System.exit(0);
    }
}

For the connection project, we use the Spring Boot default RedisConnectionFactory, which is the JedisConnectionFactory implementation provided by the Jedis Redis library.

We register the Bean defined in the listenerAdapter method as a message listener, which will listen to the messages of the chat topic.

Because the Receiver class is a POJO, it should be wrapped in a message listener adapter (implementing the MessageListener interface) so that it can be added to the connection factory by the addMessageListener method of the listener container redismessagelistener container. With this adapter, when a message arrives, it will call the receivemessage() ` method to respond.

It's that simple. After configuring the connection factory and the message listener container, you can listen to messages!

Sending messages is easier. We use StringRedisTemplate to send messages with both keys and values as strings. In the main() method, we create a Context of the Spring application, initialize the message listener container, and start listening for messages. Then get the instance of StringRedisTemplate and send a message to the chat topic. We see that the message can be successfully received and printed, done!

Keywords: Java Spring

Added by massimoGornatti on Wed, 05 Jan 2022 06:01:31 +0200