SpringBoot+Redis发布订阅模式消息队列的实现

SpringBoot+Redis发布订阅模式消息队列的实现

1、前言

一般来说,消息队列有两种场景,一种是发布/订阅模式,一种是生产者/消费者模式。功能强大的Redis不仅能做缓存支持,在消息队列方面同样支持,而且两种模式都支持。

定义: 生产者消费者模式:生产者生产消息放到队列里,多个消费者同时监听队列,谁先抢到消息谁就会从队列中取走消息;即对于每个消息只能被最多一个消费者拥有。

发布者订阅者模式:发布者生产消息放到队列里,多个监听队列的消费者都会收到同一份消息;即正常情况下每个消费者收到的消息应该都是一样的。

关于Redis其他特点以及功能在这里不再啰嗦,有兴趣的可以自行去研究,下面直接进入此次正题

第一步:创建一个SpringBoot工程,引入如下jar包

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

        <!-- 开启web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.7.0</version>
        </dependency>

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

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.1.1</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.40</version>
        </dependency>
        <dependency>
            <groupId>com.oracle</groupId>
            <artifactId>ojdbc6</artifactId>
            <version>11.2.0.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <!--Jedis-->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.0</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.46</version>
        </dependency>
    </dependencies>

2、修改application.yml配置文件

server:
  port: 8080
spring:
  redis:
    host: xxx.xx.xxx.xxx(自己redis服务ip)
    port: 6379
  primary:
    datasource:
      url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8
      username: xxx(数据库用户名)
      password: xxxxxx(密码)
      driver-class-name: com.mysql.jdbc.Driver
    #oracle
    # url: jdbc:oracle:thin:@localhost:1521:orcl
    # username: xxxx
    # password: xxxxxx
    # driver-class-name: oracle.jdbc.OracleDriver
    # max-idle: 10
    # max-wait: 10000
    # min-idle: 5
    # initial-size: 5
  secondary:
    datasource:
      url: jdbc:mysql://localhost:3306/xxl-kkk?useUnicode=true&characterEncoding=utf-8
      username: xxxx
      password: xxxxx
      driver-class-name: com.mysql.jdbc.Driver

因为此处为配的是主从库,所以有两个数据源,如果不需要可以直接去掉一个。

3、新建一个config,进行Redis相关bean的注入

@SpringBootConfiguration
public class RedisConfig {
@Bean
    public StringRedisTemplate getRedisTemplate(RedisConnectionFactory redisConnectionFactory){
        return new StringRedisTemplate(redisConnectionFactory);
    }
    @Bean(name="redisTemplate")
    public RedisTemplate<?,?> template(RedisConnectionFactory connectionFactory){
        RedisTemplate<?,?> template=new RedisTemplate<>();
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new JdkSerializationRedisSerializer());

        template.setConnectionFactory(connectionFactory);
        return template;
    }
}

两个Redis实例选一个就好,这里我用的是 RedisTemplate

4、创建一个消息实体

public class Mqmessage implements Serializable {
    private String id;
    private String content;

    public Mqmessage(String id, String content) {
        this.id = id;
        this.content = content;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }
    @Override
    public String toString() {
        return "Mqmessage{" +
                "id='" + id + '\'' +
                ", content='" + content + '\'' +
                '}';
    }
}

5、创建发布者

这里,我将发布者包装成一个Service,方便后面的测试,当然也可以直接一个main方法也是可以的,我这里图方便,就包装一个service

import java.util.logging.Logger;
@Service
public class RedisProducerServiceImpl implements RedisProducerService {
    private static Logger logger= Logger.getLogger(RedisProducerServiceImpl.class.getName());
    @Autowired
    RedisTemplate<String,String> redisTemplate;
    /**
     * 发布消息
     * @param chanal
     * @param mqmessage
     */
    @Override
    public void sendMessage(String chanal, String mqmessage) {

         redisTemplate.convertAndSend(chanal,mqmessage);
    }
}

发布消息使用**redisTemplate.convertAndSend(chanal,mqmessage);**此处省略了接口层RedisProducerService 的代码,比较简单,就是一个方法,就不贴出来了。

6、创建监听,当发布者发布消息,就进行监听并消费

在开始创建的config中加入如下bean,

@Bean
    public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
                                                   MessageListenerAdapter adapter,MessageListenerAdapter adapter1){
        RedisMessageListenerContainer container=new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        container.addMessageListener(adapter,new PatternTopic("wang"));
        container.addMessageListener(adapter1,new PatternTopic("cheng"));
        return container;
    }
    @Bean
    public MessageListenerAdapter adapter(RedisLinterMeaage meaage){
        MessageListenerAdapter messageListenerAdapter=new MessageListenerAdapter(meaage,"redisLinterMeaage");
       // messageListenerAdapter.setSerializer(new JdkSerializationRedisSerializer());
        return messageListenerAdapter;
    }
    @Bean
    public MessageListenerAdapter adapter1(RedisLinterMeaage meaage){
        MessageListenerAdapter messageListenerAdapter=new MessageListenerAdapter(meaage,"redisLinterMeaage1");
       // messageListenerAdapter.setSerializer(new JdkSerializationRedisSerializer());
        return messageListenerAdapter;
    }

7、创建订阅者,并设置两个topic

public class RedisLinterMeaage   {
    private static Logger logger=Logger.getLogger(RedisLinterMeaage.class.getName());
    
   public void redisLinterMeaage(String jsonMsg){
       logger.info("开始消费【wang】的消息");
       try{
             Mqmessage mqmessage=JSONObject.parseObject(jsonMsg,Mqmessage.class);
             System.out.println(mqmessage.getContent()+",,"+mqmessage.getId());
           logger.info("消费完毕");
       }catch (Exception e){
           logger.info("消费失败");
       }
   }
    public void redisLinterMeaage1(String jsonMsg){
        logger.info("开始消费【cheng】的消息");
        try{
            Mqmessage mqmessage=JSONObject.parseObject(jsonMsg,Mqmessage.class);
            System.out.println(mqmessage.getContent()+",,"+mqmessage.getId());
            logger.info("消费完毕");
        }catch (Exception e){
            logger.info("消费失败");
        }
    }
}

在第6步中指定了两个Topic,并写入监听,所以我在订阅者中也加了两个方法,分别对应一个Topic。

8、新建一个Controller,进行消息发布

@RestController
public class HelloWorldController {
    @Autowired
    private RedisProducerService redisProducerService;
    @RequestMapping("/getAllList")
    public Object getAllList(){
        Mqmessage mqmessage=new Mqmessage("1000","测试的");
        Mqmessage mqmessage1=new Mqmessage("10001","成的消息");
        try{
            redisProducerService.sendMessage("wang", JSON.toJSONString(mqmessage));
            redisProducerService.sendMessage("cheng",JSON.toJSONString(mqmessage1));
            return “发布消息成功”;
        }catch (Exception e){
            throw new RuntimeException(e.getMessage());
        }
    }
}

至此,Redis的消息队列发布订阅模式代码完毕,启动服务,访问localhost:8080/getAllList,就可看到控制台输出的信息,如下图
在这里插入图片描述

如有错误还请指正,毕竟还是只小菜鸟,需要努力飞翔。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值