[9] Spring Cloud Stream message-driven component

Spring Cloud Stream is a framework for building message-driven microservices. The application interacts with the binder object in Spring Cloud Stream through inputs (equivalent to message consumer) or outputs (equivalent to message producer). The Binder object is used to shield the underlying MQ details. It is responsible for intervening with specific messages. software interaction.

Solve pain points

MQ message middleware is widely used in scenarios such as application decoupling, asynchronous message processing, and traffic peak shaving.
Different MQ message middlewares have different internal mechanisms including usage methods. For example, RabbitMQ has the concept of Exchange (switch/switch), and kafka has concepts such as Topic and Partition. The differences of MQ message middleware are not conducive to us. For upper-layer development applications, when our system wants to switch from the original RabbitMQ to Kafka, we will find it more difficult, and many operations may need to be repeated (because the application is coupled with a specific MQ message middleware). get up).
Spring Cloud Stream has a good upper-level abstraction, which allows us to decouple from the specific message middleware, shielding the detailed differences of the underlying specific MQ message middleware, just like Hibernate shields the specific database (like Mysql/Oracle) . In this way
, it will become easier for us to learn, develop, and maintain MQ. Currently Spring Cloud Stream supports RabbitMQ and Kafka.

concept

inputs : (equivalent to message consumer)
outputs : (equivalent to message producer)
Binder : Use it to shield
the detailed differences between different underlying MQ message middleware. When it is necessary to change to other message middleware, All we need to do is replace the corresponding Binder binder without modifying any application logical
architecture diagram :
Insert image description here

Stream programming annotations

annotation describe
@Input (used in consumer projects) The annotation identifies the input channel through which messages received enter the application.
@Output (used in producer projects) The annotation identifies the output channel through which published messages will leave the application.
@StreamListener (used in consumer projects to monitor the arrival of messages) The listening queue is used to receive messages from the consumer's queue (with message listening...)
@EnableBinding Bind Channel and Exchange (for RabbitMQ) together

Build services

producer service

Insert image description here

  1. Create a new submodule under lagou_parent: m-cloud-stream-producer-9090
  2. Add dependencies in pom.xml
         <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>

  1. application.yml add configuration
server:
  port: 9090

spring:
  application:
    name: m-cloud-stream-producer
  cloud:
    stream:
      binders:  # 绑定MQ服务信息(此处我们是RabbitMQ)
        mRabbitMQbinder: # 给Binder定义的名称,⽤于后⾯的关联
          type: rabbit
          environment:  # MQ环境配置(⽤户名、密码等)
            spring:
              rabbitmq:
                host: 127.0.0.1
                username: guest
                password: guest
      bindings: # 关联整合通道和binder对象
       output: # output是我们定义的通道名称,此处不能乱改
         destination: m-cloud-stream-producer-exchange
         content-type: text/plain
         binder: mRabbitMQbinder


#注册发现
eureka:
  client:
    service-url:
      defaultZone: http://CloudEurekaServerA:8761/eureka,http://CloudEurekaServerB:8762/eureka
  instance:
    prefer-ip-address: true
    instance-id: ${
    
    spring.cloud.client.ip-address}:${
    
    spring.application.name}:${
    
    server.port}:@project.version@

  1. Startup class
@SpringBootApplication
@EnableDiscoveryClient
public class MCloudStreamProducer9090 {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(MCloudStreamProducer9090.class, args);
    }
}
  1. service
public interface IMessageProducer {
    
    

    public void sendMessage(String content);
}

@EnableBinding(Source.class)
public class IMessageProducerImpl implements IMessageProducer {
    
    
    @Autowired
    private Source source;

    @Override
    public void sendMessage(String content) {
    
    
        source.output().send(MessageBuilder.withPayload(content).build());
    }
}
  1. Test class
@SpringBootTest(classes = {
    
    MCloudStreamProducer9090.class})
@RunWith(SpringJUnit4ClassRunner.class)
public class MCloudStreamProducer9090Test {
    
    
    @Autowired
    private IMessageProducer iMessageProducer;

    @Test
    public void testSendMessage() {
    
    
        iMessageProducer.sendMessage("hello world");
    }
}

consumer services

  1. Create a new submodule under lagou_parent: m-cloud-stream-consumer-9091
  2. Add dependencies in pom.xml
         <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>

  1. application.yml add configuration
server:
  port: 9091

spring:
  application:
    name: m-cloud-stream-consumer
  cloud:
    stream:
      binders:  # 绑定MQ服务信息(此处我们是RabbitMQ)
        mRabbitMQbinder: # 给Binder定义的名称,⽤于后⾯的关联
          type: rabbit
          environment:  # MQ环境配置(⽤户名、密码等)
            spring:
              rabbitmq:
                host: 127.0.0.1
                username: guest
                password: guest
      bindings: # 关联整合通道和binder对象
        input: # output是我们定义的通道名称,此处不能乱改
          destination: m-cloud-stream-producer-exchange
          content-type: text/plain
          binder: mRabbitMQbinder
          group: rabbit-a


#注册发现
eureka:
  client:
    service-url:
      defaultZone: http://CloudEurekaServerA:8761/eureka,http://CloudEurekaServerB:8762/eureka
  instance:
    prefer-ip-address: true
    instance-id: ${
    
    spring.cloud.client.ip-address}:${
    
    spring.application.name}:${
    
    server.port}:@project.version@


  1. Startup class
@SpringBootApplication
@EnableDiscoveryClient
public class McloudSteamConsumer9091 {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(McloudSteamConsumer9091.class, args);
    }
}
  1. service
@EnableBinding(Sink.class)
public class MessageConsumerService {
    
    

    @StreamListener(Sink.INPUT)
    public void  receMessage(Message<String> message){
    
    
        System.out.println("=========接收到的消息:" + message);
    }
}

  • copy m-cloud-stream-consumer-9091 构建 m-cloud-stream-consumer-9092

verify

  • Producers send messages and consumers receive them
    Insert image description here
  • Messages within the same group will not be consumed repeatedly (start m-cloud-stream-consumer-9092)
    Insert image description here
    Insert image description here

Stream advanced custom message channel

Stream has two built-in interfaces, Source and Sink, which respectively define the input stream with binding "input" and the output stream with "output". We can also
customize various input and output streams (channels), but in fact we can Our service uses multiple binders, multiple input channels and output channels, but by default it has one input channel and one output channel. What should we do? We can customize message channels. Follow the example of Source and Sink and define your own name for your channel. Multiple input channels and output channels can be written in one class.

  • Define interface
interface CustomChannel {
    
    
 String INPUT_LOG = "inputLog";
 String OUTPUT_LOG = "outputLog";
 
 @Input(INPUT_LOG)
 SubscribableChannel inputLog();
 
 @Output(OUTPUT_LOG)
 MessageChannel outputLog();
}
  • In @EnableBinding the annotation, bind the custom interface
  • When using @StreamListener for monitoring, you need to specify CustomChannel.INPUT_LOG
bindings:
 inputLog:
 destination: mmExchange
 outputLog:
 destination: eduExchange

Guess you like

Origin blog.csdn.net/u014535922/article/details/130057107