Spring Cloud Stream消息中间件通过RabbitMQ实现消息推送

一、Spring Cloud Stream是什么

Spring Cloud Stream 是一个构建消息驱动微服务的框架。

Spring Cloud Stream解决了开发人员无感知的使用消息中间件的问题,因为Spring Cloud Stream对消息中间件的进一步封装,可以做到代码层面对消息中间件的无感知,甚至于动态的切换中间件(rabbitmq切换为kafka等),使得微服务开发的高度解耦,服务可以关注更多自己的业务流程;

不需要自己写配置类,直接在配置文件中配置关键信息即可

支持的消息中间件官网
在这里插入图片描述

二、为什么用Spring Cloud Stream与直接使用消息中间件对比

  • 和MQ中间件解耦:相较同样是针对MQ中间价集成的Spring Message项目,提供了更高层的面向不同MQ中间件代理(RabbitMQ、Kafka等)的Binder抽象,为开发人员提供了统一的编程模型。例如RabbitMQ原生并不支持partition特性,如果想要从Kafaka迁移到RabbitMQ,就需要修改一堆代码,但是如果是Spring Cloud Stream则有可能只需要修改几个配置即可。

三、Spring Cloud Stream 关键信息说明

在这里插入图片描述
应用程序通过input(相当于消费者consumer)、output(相当于生产者producer)来与Spring Cloud Stream中Binder交互,而Binder负责与消息中间件交互,因此,我们只需关注如何与Binder交互即可,而无需关注与具体消息中间件的交互。

组成说明
BinderBinder是应用与消息中间件之间的封装,通过Binder可以很方便的连接中间件,可以动态的改变消息类型(对应于Kafka的topic,RabbitMQ的exchange),这些都可以通过配置文件来实现;
@Input该注解标识输入通道,通过该输入通道接收消息进入应用程序
@Output该注解标识输出通道,发布的消息将通过该通道离开应用程序
@StreamListener监听队列,用于消费者的队列的消息接收
@EnableBinding将信道channel和exchange绑定在一起

消息推送流程
在这里插入图片描述

四、Spring Cloud Stream 非持久化消息

  • jar包
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
    </dependency>
    

1.生产者

  • 生产者配置文件
    spring:
      #rabbitmq配置
      rabbitmq:
        host: 192.168.10.1
        port: 30002
        username: rabbitmq
        password: rabbitmq
      cloud:
        #消息生产者
        stream:
          binders:
            # rabbitmqBinder是一个key,这个名字是一个通道的名称,在代码中会用到
            rabbitmqBinder:
              # 中间件类型
              type: rabbit
          #
          bindings:
            # @Output注解中的值
            myOutput:
              #设置要绑定的消息服务的binder,就是 rabbitmqBinder
              binder: rabbitmqBinder
              #destination表示要使用的Exchange名称定义,注意默认是Topic模式
              destination: myExchange
    
  • 自定义消息通道
    import org.springframework.cloud.stream.annotation.Output;
    import org.springframework.messaging.MessageChannel;
    
    /**
     * @Description: 自定义消息通道
     */
    public interface MessageSource {
    
        //channel名称
        String OUTPUT = "myOutput";
    
        @Output(MessageSource.OUTPUT)
        MessageChannel output();
    }
    
  • 消息发送类,此处使用的自定义管道(@EnableBinding(Source.class):为使用默认管道,key=“output”)
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.cloud.stream.annotation.EnableBinding;
    import org.springframework.messaging.support.MessageBuilder;
    
    import java.util.Date;
    
    /**
     * @Description: 消息推送
     */
    @EnableBinding(MessageSource.class)
    public class MessageSender {
    
        /**
         * 消息的发送管道
         */
        @Autowired
        private MessageSource messageSource;
    
        public void publish(String msg) {
            messageSource.output().send (MessageBuilder.withPayload(msg).build());
            System.out.println("消息发送:<" + msg + "> 完成,时间:" + new Date());
        }
    }
    
  • 消息发送Controller
    @RestController
    public class IndexController{
    
        @Autowired
        MessageSender messageSender;
    
        @RequestMapping("Sender")
        public void gen(){
            messageSender.publish("hello Stream");
        }
        
        
    }
    

2.消费者

  • 消费者配置文件
    spring:
      rabbitmq:
        host: 192.168.10.1
        port: 30002
        username: rabbitmq
        password: rabbitmq
      cloud:
        #消息生产者
        stream:
          binders:
            # rabbitmqBinder是一个key,这个名字是一个通道的名称,在代码中会用到
            rabbitmqBinder:
              # 中间件类型
              type: rabbit
          bindings:
            # 与@Input注解中值对应
            myInput:
              #设置要绑定的消息服务的binder,就是 rabbitmqBinder
              binder: rabbitmqBinder
              #destination表示要使用的Exchange名称定义,注意默认是Topic模式
              destination: myExchange
    
    
  • 自定义可订阅通道
    import org.springframework.cloud.stream.annotation.Input;
    import org.springframework.messaging.SubscribableChannel;
    
    /**
     * @Description: 自定义可订阅通道
     */
    public interface MessageSink {
        /**
         * Input channel name.
         */
        String INPUT = "myInput";
    
        /**
         * 消费者信道
         */
        @Input(MessageSink.INPUT)
        SubscribableChannel input();
    }
    
  • 自定义通道消息接收(默认@EnableBinding(Sink.class),@StreamListener(Sink.INPUT),key=“input”)
    import org.springframework.cloud.stream.annotation.EnableBinding;
    import org.springframework.cloud.stream.annotation.StreamListener;
    import org.springframework.messaging.Message;
    import java.util.Date;
    
    @EnableBinding(MessageSink.class)
    public class MessageReceiver {
    
        @StreamListener(MessageSink.INPUT)
        public void input(Message message) {
            System.out.println("消息接收:<" + message.getPayload()  + "> 完成,时间:" + new Date());
        }
    }
    

在这里插入图片描述
在这里插入图片描述

3.RabbitMQ信息

  • 交换机
    在这里插入图片描述
  • 临时队列
    在这里插入图片描述

4.缺点

rabbitmq中消息是非持久化数据,当消费者服务宕机或关闭服务重启无消费者后,生产者继续推送数据,重启后的消费者无法接受到之前的消息,造成消息丢失

五、RabbitMQ 常用模式

1.Direct 模式(直接交换模式)

该模式多了一个路由routeKey,当消息发送到交换机时,交换机在准备发送给绑定的队列时,会再判断指定的routeKey是否已和改队列进行绑定,如果未绑定,则不发送数据过去。

  • 所有发送到 Direct Exchange 的消息被转发到 RouteKey 中指定的 Queue。
  • Direct 模式可以使用 RabbitMQ 自带的 Exchange: default Exchange,所以不需要将 Exchange 进行任何绑定(binding)操作。
  • 消息传递时,RouteKey 必须完全匹配才会被队列接收,否则该消息会被抛弃,

2.Topic 模式(通配符模式,Stream 默认模式)

和路由模式类似,同样是一个生产者多个消费者,中间多了个交换机(exchange),一条消息可以被多个消费者获取。同样是传key,但是他的key是可以模糊匹配的
可以使用通配符进行模糊匹配

  • 符号’#" 匹配一个或多个词

    • 例如: 'log.#“能够匹配到’log.info.oa”
  • 符号"*”匹配不多不少一个词

    • 例如:"log.*"只会匹配到"log.erro“

3.Fanout模式(广播模式)

不处理路由键,只需要简单的将队列绑定到交换机上发送到交换机的消息都会被转发到与该交换机绑定的所有队列上。
Fanout交换机转发消息是最快的。

六、Spring Cloud Stream 持久化消息

1.配置信息

  • 消费者修改配置文件,增加group进行数据持久化

    spring:
      cloud:
        #消息生产者
        stream:
          bindings:
            # 与@Input注解中值对应
            myInput:
              # 指定分组可以进行消息持久化,分组相同只有一个消费者会消费消息
              # null或空字符串值表示匿名组不被共享。
              # null或空字符串值表示匿名组不被共享。
              # 队列名称会变为为destination.group(交换机.分组)
              group: rabbitmqGroupTwo
    

    在这里插入图片描述

  • 如果不同的消费者都想接受消息,则可以配置不同的group

2.优点

  • 此时消费端的微服务宕机或重启,该队列信息依然会被保留在 RabbitMQ中,后续依然可以进行消费;

  • 当项目集群部署了很多份,那么就会变成多个消费者,但是业务可能需要的是一个消息只消费一次,所以此时需要加个分组,就可以实现同一个分组里面的消费者只会有一个消费者能接收到消息;

七、指定路由键

默认情况下点击rabbitmq的交换机查看如图
在这里插入图片描述

  • Routing key对应的是:#
    • 表示所有消费者都可以匹配上,也可以通过指定路由键 RoutingKey实现按需求匹配消息消费端进行消息接收处理;

1.配置文件

1.消费者配置信息

  • 消费者修改配置文件,增加group进行数据持久化
    spring:
      cloud:
        #消息生产者
        stream:
          ## rabbitmq 特有的
          rabbit:
            bindings:
              # 与@Input注解中值对应
              myInput:
                # 附加特定于消费者的属性
                consumer:
                  # 设置一个RoutingKey路由key
                  bindingRoutingKey: stream.routingKey.#
              
    

八、更多配置信息

更多rabbitmq配置信息请参考如下类

  • RabbitConsumerProperties类
  • RabbitCommonProperties类

九、kafka

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-stream-kafka</artifactId>
</dependency>

配置类参考
KafkaBinderConfigurationProperties

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
好的,以下是使用Spring Cloud Stream 4.0.3和RabbitMQ实现消息发送和接收的示例: 首先,需要在项目中添加Spring Cloud StreamRabbitMQ的依赖: ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-stream-binder-rabbit</artifactId> <version>3.1.4</version> </dependency> ``` 接下来,在application.yml文件中配置RabbitMQ连接信息: ```yaml spring: rabbitmq: host: localhost port: 5672 username: guest password: guest ``` 定义消息发送和接收的接口: ```java public interface MessageChannels { String OUTPUT = "output"; @Output(OUTPUT) MessageChannel output(); } public interface MessageHandlers { String INPUT = "input"; @Input(INPUT) SubscribableChannel input(); } ``` 在需要发送消息的地方注入MessageChannels接口,并使用output()方法发送消息: ```java @Autowired private MessageChannels messageChannels; public void sendMessage(String message) { messageChannels.output().send(MessageBuilder.withPayload(message).build()); } ``` 在需要接收消息的地方注入MessageHandlers接口,并使用@StreamListener注解监听消息: ```java import org.springframework.cloud.stream.annotation.StreamListener; import org.springframework.stereotype.Component; @Component public class MessageReceiver { @StreamListener(MessageHandlers.INPUT) public void handleMessage(String message) { System.out.println("Received message: " + message); } } ``` 这样就完成了使用Spring Cloud StreamRabbitMQ实现消息发送和接收的示例。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值