【九】 Spring Cloud Stream消息驱动组件

Spring Cloud Stream 是个构建消息驱动微服务的框架。应程序通过inputs(相当于消息消费者consumer)或者outputs(相当于消息生产者producer来与Spring Cloud Stream中的binder对象交互,Binder对象是⽤来屏蔽底层MQ细节的,它负责与具体的消息中间件交互。

解决痛点问题

MQ消息中间件⼴泛应⽤在应⽤解耦合、异步消息处理、流量削峰等场景中。
不同的MQ消息中间件内部机制包括使用方式都会有所不同,比如RabbitMQ中有Exchange(交换机/交换器)这⼀概念,kafka有Topic、Partition分区这些概念,MQ消息中间件的差异性不利于我们上层的开发应用,当我们的系统希望从原有的RabbitMQ切换到Kafka时,我们会发现比较困难,很多要操作可能重来(因为应⽤程序和具体的某⼀款MQ消息中间件耦合在⼀起了)。
Spring Cloud Stream进行了很好的上层抽象,可以让我们与具体消息中间件解耦合,屏蔽掉了底层具体MQ消息中间件的细节差异,就像Hibernate屏蔽掉了具体数据库(Mysql/Oracle⼀样)。如此⼀
来,我们学习、开发、维护MQ都会变得轻松。目前Spring Cloud Stream⽀持RabbitMQ和Kafka。

概念

inputs:(相当于消息消费者consumer)
outputs:(相当于消息⽣产者producer)
Binder绑定器: 通过它来屏蔽底层不同MQ消息中间件
的细节差异,当需要更换为其他消息中间件时,我们需要做的就是更换对应的Binder绑定器⽽不需要修改任何应⽤逻辑
架构图
在这里插入图片描述

Stream编程注解

注解 描述
@Input(在消费者工程中使用) 注解标识输⼊通道,通过该输⼊通道接收到的消息进入应用程序
@Output(在生产者工程中使用) 注解标识输出通道,发布的消息将通过该通道离开应⽤程序
@StreamListener(在消费者⼯程中使用,监听message的到来) 监听队列,用于消费者的队列的消息的接收(有消息监听…)
@EnableBinding 把Channel和Exchange(对于RabbitMQ)绑定在⼀起

构建服务

生产者服务

在这里插入图片描述

  1. 在lagou_parent下新建⼦module:m-cloud-stream-producer-9090
  2. 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添加配置
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. 启动类
@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. 测试类
@SpringBootTest(classes = {
    
    MCloudStreamProducer9090.class})
@RunWith(SpringJUnit4ClassRunner.class)
public class MCloudStreamProducer9090Test {
    
    
    @Autowired
    private IMessageProducer iMessageProducer;

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

消费者服务

  1. 在lagou_parent下新建⼦module:m-cloud-stream-consumer-9091
  2. 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添加配置
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. 启动类
@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

验证

  • 生产者发送消息,消费者接收
    在这里插入图片描述
  • 同组内消息不会重复消费(启动m-cloud-stream-consumer-9092)
    在这里插入图片描述
    在这里插入图片描述

Stream⾼级之自定义消息通道

Stream 内置了两种接⼝Source和Sink分别定义了 binding 为 “input” 的输⼊流和 “output” 的输出流,
我们也可以自定义各种输⼊输出流(通道),但实际我们可以在我们的服务中使⽤多个binder、多个输入通道和输出通道,然⽽默认就带了⼀个input的输⼊通道和⼀个output的输出通道,怎么办?我们是可以自定义消息通道的,学着Source和Sink的样⼦,给你的通道定义个自己的名字,多个输⼊通道和输出通道是可以写在⼀个类中的

  • 定义接口
interface CustomChannel {
    
    
 String INPUT_LOG = "inputLog";
 String OUTPUT_LOG = "outputLog";
 
 @Input(INPUT_LOG)
 SubscribableChannel inputLog();
 
 @Output(OUTPUT_LOG)
 MessageChannel outputLog();
}
  • @EnableBinding 注解中,绑定自定义的接口
  • 使⽤ @StreamListener 做监听的时候,需要指定 CustomChannel.INPUT_LOG
bindings:
 inputLog:
 destination: mmExchange
 outputLog:
 destination: eduExchange

猜你喜欢

转载自blog.csdn.net/u014535922/article/details/130057107
今日推荐