SpringCloud-消息驱动

1、概述

Spring Cloud Stream由一个中间件中立的核组成。应用通过Spring Cloud Stream插入的input(相当于
消费者consumer,它是从队列中接收消息的)和output(相当于生产者producer,它是从队列中发送消
息的。)通道与外界交流。通道通过指定中间件的Binder实现与外部代理连接。业务开发者不再关注具
体消息中间件,只需关注Binder对应用程序提供的抽象概念来使用消息中间件实现业务即可。

2、消息提供者

1、新建项目,添加pom依赖
     <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
     </dependency>

2、编写配置文件
server:
  port: 8801
spring:
  application:
    name: stream-rabbitmq-provider
  cloud:
    stream:
      binders: # 在此处配置要绑定的rabbitmq的服务信息;
        defaultRabbit: # 表示定义的名称,用于于binding整合
          type: rabbit # 消息组件类型
          environment: # 设置rabbitmq的相关的环境配置
            spring:
              rabbitmq:
                host: xxx.xxx.xxx.xxx
                port: 5672
                username: guest
                password: guest
      bindings: # 服务的整合处理
        output: # 这个名字是一个通道的名称
          destination: studyExchange # 表示要使用的Exchange名称定义
          content-type: application/json # 设置消息类型,本次为json,文本则设置“text/plain”
          default-binder: defaultRabbit  # 设置要绑定的消息服务的具体设置
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka
  instance:
    prefer-ip-address: true
    instance-id: provider-8801.com

3、编写service
@EnableBinding(Source.class)
@Slf4j
public class MessageServiceImpl implements MessageService {

    @Autowired
    private MessageChannel output;

    @Override
    public String send() {
        String serial = IdUtil.randomUUID();
        log.info("*****流水号:" + serial);
        output.send(MessageBuilder.withPayload(serial).build());
        return serial;
    }
}

4、编写controller
    @Autowired
    private MessageService service;

    @Value("${server.port}")
    private String port;

    @GetMapping("/sendMsg")
    public String sendMsg(){
        String msg = service.send();
        return "端口:" + port + ",消息发送者发送消息:" + msg;
    }

5、访问rabbitmq的15672端口可以看到发送的信息波峰

3、消息消费者

1、新建项目,添加pom依赖
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
    </dependency>

2、编写配置文件
server:
  port: 8803

spring:
  application:
    name: stream-rabbitmq-consumer
  cloud:
    stream:
      binders: # 在此处配置要绑定的rabbitmq的服务信息;
        defaultRabbit: # 表示定义的名称,用于于binding整合
          type: rabbit # 消息组件类型
      bindings: # 服务的整合处理
        myInput: # 这个名字是一个通道的名称
          destination: studyExchange # 表示要使用的Exchange名称定义
          content-type: application/json # 对象json,文本则设置“text/plain”
          default-binder: defaultRabbit # 设置要绑定的消息服务的具体设置
  rabbitmq:
    host: xxx.xxx.xxx.xxx
    port: 5672
    username: guest
    password: guest
eureka:
  instance:
    prefer-ip-address: true
    instance-id: consumer-8803.com
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka

注意上面的bindings下的myInput可以自己指定名字,提供者使用的output可以通过Source.class直接引用,如果使用自定义的名字,需要编写一个接口:

3、编写接口
public interface MyStream {

    String myInput = "myInput";

    @Input(MyStream.myInput)
    SubscribableChannel input();
}

4、编写消费者类
@Component
@EnableBinding(MyStream.class)
@Slf4j
public class ReceviceMessageController {

    @Value("${server.port}")
    private String port;

    @StreamListener(MyStream.myInput)
    public void input(Message<String> msg){
        log.info("消费者8803,端口:" + port + ",收到消息:" + msg.getPayload());
    }
}
注意这里的@EnableBinding(MyStream.class)不是用的Sink.class,Sink.class引用的名字为input,此处使用的是自定义名字。

5、启动提供者和消费者,提供者发送信息,消费者可以接收到。

4、消息重复消费问题

1、将上述消费者clone一份,发现发送消息会被消费两次,因为广播的类型是topic,凡是订阅的都可以接收

2、在两个消费者的配置文件上给其分组,添加相同的group即可
spring:
  cloud:
    stream:
      bindings: # 服务的整合处理
        myInput: # 这个名字是一个通道的名称
          group: groupA

3、相同的分组之间只会被一个消费者消费,例如出现第三个消费者,分组是groupB,发送消息后,第一和第二个消费者只有一个人可以消费到消息,第三个消费者可以一直收到信息,因为他自己一组。

5、消息持久化

1、没有被分组的消费者在关闭服务的时候发送消息,启动消费者不会收到已经发送的消息

2、被分组的消费者在关闭服务的时候发送消息,启动消费者会收到之前已经发送的消息

猜你喜欢

转载自blog.csdn.net/wx774891/article/details/106904249
今日推荐