springboot整合redis实现消息队列–异步接收、多线程发送

一、发布消息到redis

1.新建springboot项目

新建springboot项目redis-queue。

2.引入依赖

引入相关依赖,其中用到了lombok,需要安装lombok插件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.0.RELEASE</version>
        <relativePath/>
    </parent>
    <groupId>com.lpl</groupId>
    <artifactId>redis-queue</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>redis-queue</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

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

        <!--springboot web场景依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--属性配置支持,使用传统的xml或properties配置时需要此注解的支持-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

        <!--springboot redis场景依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <!--默认继承lettuce,切换成jedis需要排除依赖-->
            <exclusions>
                <exclusion>
                    <groupId>io.lettuce</groupId>
                    <artifactId>lettuce-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--加入jedis-->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>

        <!--lombok依赖-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!--alibaba json-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.28</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
   
    <!--springboot maven插件,以maven方式提供对springboot的支持,将springboot项目打包为传统的jar活war运行-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

3.编写配置文件

编写application.properties配置文件,配置redis连接信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
server.port=8000

#redis单机版配置

spring.redis.database=0
spring.redis.host=192.168.2.75
spring.redis.port=6379
#spring.redis.password=连接密码(默认为空)
#连接池中最小空闲连接
spring.redis.jedis.pool.min-idle=0
#连接池中最大空闲连接
spring.redis.jedis.pool.max-idle=8
#连接池中最大连接数(负数表示没有限制)
spring.redis.jedis.pool.max-active=8
#连接池中最大阻塞等待时间(单位毫秒,负值表示没有限制)
spring.redis.jedis.pool.max-wait=-1
#redis监听的server名称
#spring.redis.sentinel.master=myMaster
#哨兵的配置列表
#spring.redis.sentinel.nodes=192.168.2.76:26379,192.168.2.77:26379
#连接超时时间(单位毫秒,为0表示无限制)
spring.redis.timeout=0
#不使用ssl加密
spring.redis.ssl=false


#redis集群版配置
#集群中各主从节点
#spring.redis.cluster.nodes=192.168.2.75:7001,192.168.2.75:7002,192.168.2.75:7003,192.168.2.75:7004,192.168.2.75:7005,192.168.2.75:7006
#最大重定向次数(由于集群中数据存储在多个节点,所以在访问数据时需要通过转发进行数据定位)
#spring.redis.cluster.max-redirects=2

4.编写实体类

消息实体Message.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.lpl.bean;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;

/**
 * 发送的消息实体
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Message implements Serializable {

    private String id;          //消息id
    private String personNo;    //发送人的学工号(可指定多个,以逗号隔开,不超过1000个)
    private String title;       //消息标题
    private String content;     //消息内容
    private String type;        //消息类型,system(系统消息)、sms(短信消息)
    private Date createTime;    //创建时间
    private Date updateTime;    //更新时间
    private String statusCode;  //消息发送结果状态码(4000表示成功,4001表示失败)
   
}

结果常量类ConstantResult.java

1
2
3
4
5
6
7
8
9
10
package com.lpl.common;

/**
 * 系统中一些变量定义
 */
public class ConstantResult {

    public static final String SUCCESS_CODE = "200";    //成功状态码
    public static final String FAIL_CODE = "500";       //失败状态码
}

公共返回结果类CommonResult.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.lpl.common;

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

/**
 * 返回的指定公共结果
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CommonResult<T> {

    private String code;    //返回状态码
    private String msg;     //返回提示信息
    private T data;         //返回数据

    public CommonResult(String code, String msg){
        this.code = code;
        this.msg = msg;
    }

}

5.编写redis配置类

我们操作redis需要用到RedisTemplate,编写redis配置类RedisConfig.java。这里配置了多个消息监听适配器以通过不同的方法去监听、订阅不同的redis channel消息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package com.lpl.config;

import com.lpl.listener.Receiver;
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 org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * redis自定义配置类
 */
@Configuration
public class RedisConfig {

    /**
     * 返回一个RedisTemplate Bean
     * @param redisConnectionFactory    如果配置了集群版则使用集群版,否则使用单机版
     * @return
     */
    @Bean(name = "redisTemplate")
    public RedisTemplate<?, ?> getRedisTemplate(RedisConnectionFactory redisConnectionFactory){

        RedisTemplate<?, ?> template = new RedisTemplate<>();
        //设置key和value序列化机制
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new Jackson2JsonRedisSerializer<Object>(Object.class));
        template.setConnectionFactory(redisConnectionFactory);  //设置单机或集群版连接工厂

        return template;
    }

    /**
     * 系统消息适配器
     * @param receiver
     * @return
     */
    @Bean(name = "systemAdapter")
    public MessageListenerAdapter systemAdapter(Receiver receiver){
        //指定类中回调接收消息的方法
        MessageListenerAdapter adapter = new MessageListenerAdapter(receiver, "systemMessage");
        //adapter.afterPropertiesSet();
        return adapter;
    }

    /**
     * 短信消息适配器
     * @param receiver
     * @return
     */
    @Bean(name = "smsAdapter")
    public MessageListenerAdapter smsAdapter(Receiver receiver){
        //指定类中回调接收消息的方法
        MessageListenerAdapter adapter = new MessageListenerAdapter(receiver, "smsMessage");
        //adapter.afterPropertiesSet();
        return adapter;
    }

    /**
     * 构建redis消息监听器容器
     * @param connectionFactory
     * @param systemAdapter
     * @param smsAdapter
     * @return
     */
    @Bean
    public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
                                                   MessageListenerAdapter systemAdapter, MessageListenerAdapter smsAdapter){
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        //指定不同的方法监听不同的频道
        container.addMessageListener(systemAdapter, new PatternTopic("system"));
        container.addMessageListener(smsAdapter, new PatternTopic("sms"));
        return container;
    }
}

若要使用redis集群版,需要增加如下配置类:
读取集群配置属性类RedisClusterProperty.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.lpl.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import java.util.List;

/**
 * redis集群配置属性,在redis实例工厂提供参数配置
 */
@Component
@Validated
@Data
@ConfigurationProperties(value = "spring.redis.cluster")
public class RedisClusterProperty {

    private List<String> nodes;     //集群各节点ip和port

}

redis集群配置类RedisClusterConfig.java,当我们配置类集群版连接工厂时,创建RedisTemplate时就会使用此工厂进行创建,此时使用的就是集群版。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.lpl.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.stereotype.Component;

/**
 * redis集群版配置
 */
@Configuration
@Component
public class RedisClusterConfig {

    @Autowired
    private RedisClusterProperty redisClusterProperty;

    /**
     * 配置返回RedisConnectionFactory连接工厂
     * @return
     */
    @Bean
    @Primary    //若有相同类型的Bean时,优先使用此注解标注的Bean
    public RedisConnectionFactory connectionFactory(){
        RedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory(
                new RedisClusterConfiguration(redisClusterProperty.getNodes()));

        return redisConnectionFactory;
    }

}

6.编写Service层

消息发布业务层接口PublisherService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.lpl.service;

import com.lpl.bean.Message;
import com.lpl.common.CommonResult;

/**
 * 消息发布者接口
 */
public interface PublisherService {

    /**
     * 发布消息到redis
     * @param message 消息对象
     * @return
     */
    CommonResult pubMsg(Message message);
}

消息发布业务层接口实现类PublisherServiceImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package com.lpl.service.impl;

import com.lpl.bean.Message;
import com.lpl.common.CommonResult;
import com.lpl.common.ConstantResult;
import com.lpl.service.PublisherService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.Date;
import java.util.UUID;

/**
 * 消息发布者service实现类
 */
@Service
public class PublisherServiceImpl implements PublisherService {

    @Autowired
    private RedisTemplate<String, Message> redisTemplate;

    /**
     * 发送消息到redis频道供订阅。注意:使用redis客户端redis-cli登录订阅查看的中文内容是以16进制的形式
     *      表示的,若要查看中文字符,需要在连接时强制原始输出 redis-cli -h localhost -p 6379 --raw
     *      然后再使用命令订阅频道     subscribe system
     * @param message 消息对象
     * @return
     */
    @Override
    public CommonResult pubMsg(Message message) {
        //返回结果
        CommonResult result = null;
        if (null != message){
            //补全消息实体
            if (StringUtils.isEmpty(message.getId())){  //如果为传id则生成并返回
                message.setId(UUID.randomUUID().toString());
            }
            message.setCreateTime(new Date());
            message.setUpdateTime(new Date());
            try{
                redisTemplate.convertAndSend(message.getType(), message);    //往指定频道发布消息
                //redisTemplate.opsForList().leftPush(message.getType(), message);    //采用队列的形式发布到redis
                System.out.println("消息发布到redis队列频道:" + message.getType() + "成功!");
                result = new CommonResult<Message>(ConstantResult.SUCCESS_CODE, "消息发布到" + message.getType() + "频道成功!", message);
            }catch (Exception e){
                e.printStackTrace();
                result = new CommonResult<Message>(ConstantResult.FAIL_CODE, "消息发布到" + message.getType() + "频道失败!", message);
            }
        }
        return result;
    }
}

7.编写Controller层

消息发布者controller接口,PublisherController.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.lpl.controller;

import com.lpl.bean.Message;
import com.lpl.common.CommonResult;
import com.lpl.service.PublisherService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

/**
 * 消息发布者controller
 */
@RestController
public class PublisherController {

    private static final Logger logger = LoggerFactory.getLogger(PublisherController.class);

    @Autowired
    private PublisherService publisherService;

    /**
     * 发布消息到redis指定频道
     * @param message
     * @return
     */
    @PostMapping("/pubMsg")
    public CommonResult pubMsg(@RequestBody Message message){
        CommonResult commonResult = publisherService.pubMsg(message);
        return commonResult;
    }
}

8.消息发布测试

启动项目,我们可以使用postman工具调用发送消息到redis。如下图调用:
发布消息调用
使用redic-cli客户端登录redis并使用–raw强制原始输出(否则订阅查看到的中文内容是以16进制展示的)。

1
./redis-cli -h localhost -p 6379 --raw

然后使用命令订阅相应频道消息。

1
subscribe sms

这里,我们看到消息已经发布到指定的频道
订阅消息查看

二、异步接收、多线程消费消息

1.编写消息监听类

消息监听类Receiver.java,我们在RedisConfig.java类中已经指定了该类中各方法对应监听的redis channel,当有消息发布到channel时,该类中对应的方法就会监听到这些消息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.lpl.listener;

import com.alibaba.fastjson.JSONObject;
import com.lpl.bean.Message;
import com.lpl.service.SendAndStorageProcess;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 消息接收侦听器
 */
@Component
public class Receiver{

    @Autowired
    private SendAndStorageProcess sendAndStorageProcess;

    private AtomicInteger counter = new AtomicInteger();    //消息计数器

    /**
     * 接收系统消息,开启异步监听
     * @param message
     */
    @Async
    public void systemMessage(String message){
        int counter = this.counter.incrementAndGet();
        System.out.println("接收到第" + counter + "条消息!!频道为:system,消息内容为======:");
        //将消息内容字符串转化为对象
        Message messageObject = JSONObject.parseObject(message, Message.class);
        System.out.println(messageObject.getContent());

        //TODO 开启多线程调用发送并处理消息
        JSONObject result = sendAndStorageProcess.sendAndStorageMsg(messageObject);
    }

    /**
     * 接收短信消息,开启异步监听
     * @param message
     */
    @Async
    public void smsMessage(String message){
        int counter = this.counter.incrementAndGet();
        System.out.println("接收到第" + counter + "条消息!!频道为:sms,消息内容为======:");
        //将消息内容字符串转化为对象
        Message messageObject = JSONObject.parseObject(message, Message.class);
        System.out.println(messageObject.getContent());

        //TODO 开启多线程调用发送
        JSONObject result = sendAndStorageProcess.sendAndStorageMsg(messageObject);
    }

}

2.开启异步接收

在主类中开启异步支持(注意:需要开启异步的方法不能是private修饰),在Receiver.java类中的监听方法已经开启了异步。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.lpl;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

import java.util.concurrent.Executor;

/**
 * 关于redis单机切换到集群,打开application.properties文件的redis集群配置和RedisClusterConfig文
 *      件的RedisConnectionFactory Bean注册配置。
 */
@SpringBootApplication
@EnableAsync
public class RedisQueueCacheApplication {

    public static void main(String[] args) {
        SpringApplication.run(RedisQueueCacheApplication.class, args);
    }
}

3.编写线程池配置类

线程池配置类TaskExecutorConfig.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package com.lpl.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 线程池配置类
 */
@Configuration
public class TaskExecutorConfig {

    /**
     * 创建一个线程池
     * @return
     */
    @Bean(name = "threadTaskExecutor")
    public ThreadPoolTaskExecutor getThreadPoolTaskExecutor(){
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);   //核心线程池大小
        executor.setMaxPoolSize(50);    //最大线程池大小
        executor.setQueueCapacity(1000);    //任务队列大小
        executor.setKeepAliveSeconds(300);  //线程池中空闲线程等待工作的超时时间(单位秒)
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());    //线程拒绝策略,此策略提供简单的反馈控制机制,能够减缓新任务的提交速度

        return executor;
    }

    /**
     * 创建一个固定大小的线程池
     * @return
     */
    @Bean(name = "fixedThreadPool")
    public ExecutorService executorService(){
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10);
        return fixedThreadPool;
    }

}

4.编写消息处理类

消息处理类(多线程处理)SendAndStorageProcess.java,类中发消息的方法使线程休眠了两秒,模拟发消息的相对耗时操作,用于验证多线程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package com.lpl.service;

import com.alibaba.fastjson.JSONObject;
import com.lpl.bean.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;

/**
 *  发送和存储消息任务
 */
@Component
public class SendAndStorageProcess{

    @Autowired
    private ThreadPoolTaskExecutor threadTaskExecutor;  //注入线程池

    /**
     * 多线程调用发送消息
     * @param message
     * @return
     */
    public JSONObject sendAndStorageMsg(Message message) {

        Future<JSONObject> future = threadTaskExecutor.submit(new Callable<JSONObject>() {  //采用带返回值的方式
            @Override
            public JSONObject call() throws Exception {

                //1.调用相对比较耗时的发消息方法
                String code = sendMessage(message);
                message.setUpdateTime(new Date());
                if ("200".equals(code)){    //发送成功
                    message.setStatusCode("4000");
                }else{  //发送失败
                    message.setStatusCode("4001");
                }

                //2.存储消息
                storageMessage(message);

                JSONObject result = new JSONObject();
                result.put("code", "200");
                result.put("msg", "发送消息成功!");
                return result;
            }
        });

        JSONObject jsonResult = new JSONObject();   //返回结果
        try{
            if (future.isDone()){   //线程调度结束时,才获取结果
                jsonResult = future.get();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return jsonResult;      //消息发送与存储结果
    }

    /**
     * 调用接口发送消息
     * @param message
     * @return
     */
    private String sendMessage(Message message) {
        try{
            //TODO 这里写一些发消息的业务逻辑

            Thread.sleep(2000);     //增加耗时操作,查看多线程效果
            System.out.println(Thread.currentThread().getName() + "线程发送消息成功,消息内容:" + message.getContent());
            return "200";   //发送消息结果状态码
        }catch (Exception e){
            System.out.println(Thread.currentThread().getName() + "线程发送消息失败,消息内容:" + message.getContent());
            e.printStackTrace();
        }
        return "500";   //发送消息结果状态码
    }

    /**
     * 存消息到数据库
     * @param message
     * @return
     */
    private void storageMessage(Message message) {
        try{
            //TODO 这里执行插入消息到数据操作
            System.out.println(Thread.currentThread().getName() + "线程插入消息到数据库成功,消息内容:" + message.getContent());
        }catch (Exception e){
            System.out.println(Thread.currentThread().getName() + "线程插入消息到数据库失败,消息内容:" + message.getContent());
            e.printStackTrace();
        }
    }
}

5.消息消费测试

快速调用接口,看到如下打印,已经实现了异步、多线程发送效果。
消息消费
OVER,如有错误!感谢指正!