The reason for writing this article should be attributed to πŸ‘‡

In my last blog post, I wrote that πŸ‘‰ SpringBoot integrates Redis with the publish/subscribe model

And the last blog about πŸ‘‰Docker building a Redis Cluster environment

I think for each knowledge point, the light does not operate is useless (forget too fast…) , how many times in the hand can be used to deepen the impression on it.

Yesterday we set up the Redis Cluster environment, today we play with the Redis message queue

So you have this Demo of Redis implementing message queues,

Like a sentence: “eight hours for life, eight hours for development”.

‘😁.

Location: Clouds seen at home

Author: 😁

One, foreword

concept

Message queue: A “message queue” is a container that holds messages while they are in transit.

It’s a producer-queue – consumer model. Clustering is just more and more.

Function:

It mainly solves application coupling, asynchronous message, traffic cutting and other problems

Application scenario:

Four scenarios include asynchronous processing, decoupling (splitting multiple systems), traffic peaking (killing activities and excessive requests), and message communication (publishing announcements and logging).

Only the simplest diagram is shown here.

Example: asynchronous messages

After using message queues

In fact, there are a lot of message middleware in the market, such as RabbitMq,RocketMq, ActiveMq, Kafka, etc., I take Redis as message queue, its intention is 1) to get familiar with Redis; 2) Redis can do simple message queuing

Two, early preparation

You just need a Redis, but the rest is nothing special. 😁

2.1. Project Structure

A common SpringBoot project… 😊

2.2. Dependent JAR packages

Jars are normal jar packages, nothing new. 😜

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.5.2</version>
    <relativePath/> <! -- lookup parent from repository -->
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
        <version>2.4.3</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.72</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>
Copy the code

2.3. Yml configuration file

Separate stand-alone and cluster, mainly the previous article with…. πŸ™„ 😢

Single-machine configuration file

spring:
  redis:
    database: 0
    port: 6379
    host: localhost
    password:
    lettuce:
      pool:
        Maximum number of connections in the connection pool (negative value indicates no limit)
        max-active: 1024
        # Connection pool maximum blocking wait time (negative value indicates no limit)
        max-wait: 10000
        # Maximum free connection in the connection pool
        max-idle: 200
        # Minimum free connection in the connection pool
        min-idle: 0
    # Connection timeout (milliseconds)
    timeout: 10000
Copy the code

Redis cluster configuration file

server:
  port: 8089
spring:
  application:
    name: springboot-redis
  redis:
    password: 1234
    cluster:
      nodes:
        - IP address: 6379
        - IP address: 6380
        - IP address: 6381
        - IP address: 6382
        - IP address: 6383
        - IP address: 6384
      max-redirects: 3  # Obtain the maximum number of failed redirects
    lettuce:
      pool:
        max-active: 1000  Maximum number of connections in the connection pool (negative value indicates no limit)
        max-idle: 10 # Maximum free connection in the connection pool
        min-idle: 5 # Minimum free connection in the connection pool

# = = = = = = = = = = = jedis configuration way = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# jedis:
# pool:
# max-active: 1000 # Maximum number of connections in the connection pool
# Max -wait: -1ms # Max -wait: -1ms
# max-idle: 10 # Maximum idle connection in the connection pool
# min-idle: 5 # minimum idle connection in the connection pool
#
Copy the code

Three, coding

3.1, the config layer

No special configuration, πŸ€—

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
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.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/** * Redis configuration class * 1. Set RedisTemplate serialization/deserialization **@author cuberxp
 * @since 1.0.0
 * Create time 2020/1/23 0:06
 */
@Configuration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // Set the serialization of the value hashValue value
        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<Object>(
                Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        serializer.setObjectMapper(om);
        redisTemplate.setValueSerializer(serializer);
        redisTemplate.setHashValueSerializer(serializer);
        // Key hasKey serialization
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.afterPropertiesSet();
        returnredisTemplate; }}Copy the code

3.2. Information Entity class

Add an entity class to simulate the entity class that you need to pass information to.

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

/ * * *@author crush
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class AnnouncementMessage implements Serializable {

    private static final long serialVersionUID = 8632296967087444509L;

    private String id;

    / * * * * /
    private String content;
}

Copy the code

3.3, MyThread class

Starts as the project starts.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

/ * * *@Author: crush
 * @Date: 2021-08-06 22:17 * version 1.0 * ApplicationRunner: * used to indicate which SpringApplication should be run when the bean contains the SpringApplication. * When the project is running, it will automatically run. * /
@Component
public class MyThread implements ApplicationRunner {

    @Autowired
    MessageConsumerService messageConsumerService;

    @Override
    public void run(ApplicationArguments args) throws Exception { messageConsumerService.start(); }}Copy the code

3.4. Consumers

import java.util.concurrent.TimeUnit;
import com.crush.queue.entity.AnnouncementMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;


/** * ApplicationRunner implements this interface that can be started with project startup *@author crush
 */
@Service
public class MessageConsumerService extends Thread {


    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    private volatile boolean flag = true;

    private String queueKey="queue";

    private Long popTime=1000L;

    @Override
    public void run(a) {
        try {
            AnnouncementMessage message;
            // In order to keep the loop going without ending
            while(flag && ! Thread.currentThread().isInterrupted()) { message = (AnnouncementMessage) redisTemplate.opsForList().rightPop(queueKey,popTime,TimeUnit.SECONDS); System.out.println("Received."+ message); }}catch(Exception e) { System.err.println(e.getMessage()); }}public boolean isFlag(a) {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag; }}Copy the code

3.5 Producers

import com.crush.queue.entity.AnnouncementMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

@Service
public class MessageProducerService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    private String queueKey="queue";
    
    public Long sendMeassage(AnnouncementMessage message) {
        System.out.println("Sent." + message);
        returnredisTemplate.opsForList().leftPush(queueKey, message); }}Copy the code

Four, test,

I simply wrote a test code. 😝

import com.crush.queue.entity.AnnouncementMessage;
import com.crush.queue.service.MessageConsumerService;
import com.crush.queue.service.MessageProducerService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/ * * *@Author: crush
 * @Date: 2021-08-06 17:11
 * version 1.0
 */
@SpringBootTest
public class MessageQueueTest {
    @Autowired
    private MessageProducerService producer;

    @Autowired
    private MessageConsumerService consumer;

    /** * This test time first start the main start tired, * then the consumer can always listen. * /
    @Test
    public void testQueue2(a) {
        producer.sendMeassage(new AnnouncementMessage("1"."aaaa"));
        producer.sendMeassage(new AnnouncementMessage("2"."bbbb"));
        try {
            Thread.sleep(1000L);
        } catch(InterruptedException e) { e.printStackTrace(); }}}Copy the code

Note: This is only a small demo, many details have not been considered, just a preliminary study of Redis message queue, forgive me.

5. Talk to yourself

A blog started by building a Redis Cluster is finally over, forget it seems not yet, I feel next time I can write more practical. πŸ˜‚ 🀣

I don’t know what kind of learning is, the blogger’s own feeling is learned, through their own to comb through, or to practice, I think this way, whether for understanding or memory, will be more profound.

If there are deficiencies, please do not give instruction!! 😁

If you have any doubts, you can leave a message or a private message, and you will be the first to reply. πŸ‘© πŸ’»

That’s all for this article, see you next time. πŸ‘‰ An article implementing message queues with Redis (still working on)