[SpringCloud] Stream message notification usage

Overview

Shield the differences in underlying message middleware and reduce switching costs. Unified messaging programming model
official website:
https://spring.io/projects/spring-cloud-stream#overview
https://cloud.spring.io/spring-cloud- static/spring-cloud-stream/3.0.1.RELEASE/reference/html/
中文:
https://m.wang1314.com/doc/webapp/topic/20971999.html
By defining the binder as the middle layer, it works perfectly Implements isolation between application and message middleware details.
By exposing a unified Channel to applications, applications no longer need to consider various message middleware implementations.

StandardMQ

Insert image description here

Configuration

POM

<dependency>
   <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>

YML

server:
  port: 8801

spring:
  application:
    name: cloud-stream-provider
  cloud:
      stream:
        binders: # 在此处配置要绑定的rabbitmq的服务信息;
          defaultRabbit: # 表示定义的名称,用于于binding整合
            type: rabbit # 消息组件类型
            environment: # 设置rabbitmq的相关的环境配置
              spring:
                rabbitmq:
                  host: localhost
                  port: 5672
                  username: guest
                  password: guest
        bindings: # 服务的整合处理
          output: # 这个名字是一个通道的名称
            destination: studyExchange # 表示要使用的Exchange名称定义
            content-type: application/json # 设置消息类型,本次为json,文本则设置“text/plain”
            binder: defaultRabbit # 设置要绑定的消息服务的具体设置

eureka:
  client: # 客户端进行Eureka注册的配置
    service-url:
      defaultZone: http://localhost:7001/eureka
  instance:
    lease-renewal-interval-in-seconds: 2 # 设置心跳的时间间隔(默认是30秒)
    lease-expiration-duration-in-seconds: 5 # 如果现在超过了5秒的间隔(默认是90秒)
    instance-id: send-8801.com  # 在信息列表时显示主机名称
    prefer-ip-address: true     # 访问的路径变为IP地址

Example

message sending

  1. interface
public interface IMessageProvider
{
    
    
    public String send() ;
}
  1. Implementation class
@EnableBinding(Source.class) // 可以理解为是一个消息的发送管道的定义
public class MessageProviderImpl implements IMessageProvider
{
    
    
    @Resource
    private MessageChannel output; // 消息的发送管道

    @Override
    public String send()
    {
    
    
        String serial = UUID.randomUUID().toString();
        this.output.send(MessageBuilder.withPayload(serial).build()); // 创建并发送消息
        System.out.println("***serial: "+serial);

        return serial;
    }
}
  1. Controller
@RestController
public class SendMessageController
{
    
    
    @Resource
    private IMessageProvider messageProvider;

    @GetMapping(value = "/sendMessage")
    public String sendMessage()
    {
    
    
        return messageProvider.send();
    }
}

Configure the RabbitMQ visualization plug-in

rabbitmq-plugins enable rabbitmq_management
http://localhost:15672/

message consumer

  1. POM
<dependency>
   <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--基础配置-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
  1. Controller
@Component
@EnableBinding(Sink.class)
public class ReceiveMessageListenerController
{
    
    
    @Value("${server.port}")
    private String serverPort;


    @StreamListener(Sink.INPUT)
    public void input(Message<String> message)
    {
    
    
        System.out.println("消费者1号,----->接受到的消息: "+message.getPayload()+"\t  port: "+serverPort);
    }
}

Problems encountered

  1. There is a problem of repeated consumption
  2. Message persistence issues

recurrent

For example, in the following scenario, when we deploy the order system in a cluster, we will obtain the order information from RabbitMQ.
If an order is obtained by two services at the same time, it will cause data errors. We must avoid this situation.
At this time, we can use message grouping in Stream to solve
Insert image description here
the problem. Note that multiple consumers in the same group in Stream are in a competitive relationship, which can ensure that the message will only be consumed once by one of the applications.
Different groups can be fully consumed (repeated consumption), but
competition will occur within the same group, and only one of them can consume.

Solution: Modify YML

Add group

spring:
  application:
    name: cloud-stream-consumer
  cloud:
      stream:
        binders: # 在此处配置要绑定的rabbitmq的服务信息;
          defaultRabbit: # 表示定义的名称,用于于binding整合
            type: rabbit # 消息组件类型
            environment: # 设置rabbitmq的相关的环境配置
              spring:
                rabbitmq:
                  host: localhost
                  port: 5672
                  username: guest
                  password: guest
        bindings: # 服务的整合处理
          input: # 这个名字是一个通道的名称
            destination: studyExchange # 表示要使用的Exchange名称定义
            content-type: application/json # 设置消息类型,本次为对象json,如果是文本则设置“text/plain”
            binder: defaultRabbit # 设置要绑定的消息服务的具体设置
            group: atguiguA

For multiple microservice instances of the same consumer group, only one will get it each time

Notice

If it is not assigned to a consumer group, it will not be persisted, and unconsumed messages will be lost

Guess you like

Origin blog.csdn.net/qq_45742250/article/details/132363538