SpringCloud(十一):Stream消息驱动 + RabbitMQ【Greenwich 版】

Spring Cloud Stream 的 binder 负责与消息中间件交互(和消息中间件解耦,不需要关注具体的消息中间件)应用通过Spring Cloud Stream插入的input(相当于消费者consumer,它是从队列中接收消息的)和output(相当于生产者producer,它是从队列中发送消息的。)通道与外界交流。当需要升级消息中间件,或者是更换其他消息中间件产品时,我们需要做的就是更换对应的Binder绑定器而不需要修改任何应用逻辑。
在这里插入图片描述

Stream内置接口

Stream内置了三个接口,分别是Source,Sink,Processor

Source是输出通道,通道名是output

public interface Source {
    String OUTPUT = "output";

    @Output("output")
    MessageChannel output();
}

Sink是输入通道,通道名是input

public interface Sink {
    String INPUT = "input";

    @Input("input")
    SubscribableChannel input();
}

Processor即是输入通道,也是输出通道,通道名是output,input

public interface Processor extends Source, Sink {
}

下面我们使用stream提供的三个通道来做一个demo

  1. 生产者发送消息到中转者
  2. 中转者接收消息并对消息做出修改,接着中转者将消息发送给消费者
  3. 消费者消费消息

下面三个模块的启动类都不变,使用默认的就好,就不贴出来了

创建消息发送者

新建模块stream-producer-8013,添加依赖,为了方便就不将服务注册到注册中心了,等会测试只需要启动这三个模块就可以了

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

添加配置

server:
  port: 8013
spring:
  application:
    name: stream-producer
  cloud:
    stream:
      binders: #在此处配置要绑定的rabbitmq的服务信息
        myrabbit: #自定义的名称
          type: rabbit #消息组件类型
          environment: #设置rabbitmq的相关的环境配置
            spring:
              rabbitmq:
                host: 127.0.0.1
                port: 5672
                username: guest
                password: guest
      bindings:
        output: #绑定的通道,这里使用的是stream提供的输出通道
          destination: msg #发送的目的地
          content-type: application/json #消息类型

创建一个user类,等会发送消息就发送这个user

public class User implements Serializable {
    private int id;
    private String name;

    public User() {
    }

    public User(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

创建消息发送者来发送消息

//绑定输出通道
@EnableBinding(Source.class)
public class Producer {
    @Autowired
    private Source source;

    public void sendMsg(User user){
	    //发送消息
        source.output().send(MessageBuilder.withPayload(user).build());
    }
}

提供一个访问接口

@RestController
public class ProducerController {
    @Autowired
    private Producer producer;

    @RequestMapping("/sendMsg")
    public void sendMsg(){
        User user = new User(1,"小王");
        producer.sendMsg(user);
    }
}

至此,消息发送者创建完毕

创建消息中转者

创建stream-transfer-8014模块,添加依赖

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

添加配置

server:
  port: 8014
spring:
  application:
    name: stream-producer
  cloud:
    stream:
      binders: #在此处配置要绑定的rabbitmq的服务信息
        myrabbit: #自定义的名称
          type: rabbit #消息组件类型
          environment: #设置rabbitmq的相关的环境配置
            spring:
              rabbitmq:
                host: 127.0.0.1
                port: 5672
                username: guest
                password: guest
      bindings:
        input: #绑定的通道,这里使用的是stream提供的输入通道
          destination: msg #从该目的地接受消息,上面消息发送者是向这个目的地发送消息
          content-type: application/json #消息类型
        output: #绑定的通道,这里使用的是stream提供的输出通道
          destination: transfer-msg #消息中转者等会向这个目的地发送消息
          content-type: application/json #消息类型

创建消息中转者

//绑定Processor通道
@EnableBinding(Processor.class)
public class Transfer {
    /**
     * 监控input通道,接收到的消息就是obj,最后发送加工过的消息到output通道
     * @param obj 接收到的消息
     * @return 加工后的消息
     */
    @ServiceActivator(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT)
    public Object getMsg(Object obj){
    	//这里先将消息输出,再返回加工后的消息
        System.out.println(obj);
        return "经过中转者加工过的消息:"+obj;
    }
}

至此,消息中转者创建完毕

创建消息消费者

创建模块stream-consumer-8015,添加依赖

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

添加配置

server:
  port: 8015
spring:
  application:
    name: stream-producer
  cloud:
    stream:
      binders: #在此处配置要绑定的rabbitmq的服务信息
        myrabbit: #自定义的名称
          type: rabbit #消息组件类型
          environment: #设置rabbitmq的相关的环境配置
            spring:
              rabbitmq:
                host: 127.0.0.1
                port: 5672
                username: guest
                password: guest
      bindings:
        input: #绑定的通道,这里使用的是stream提供的输入通道
          destination: transfer-msg #从该目的地接受消息,上面消息中转者是向这个目的地发送消息
          content-type: application/json #消息类型

创建消息消费者

//绑定输入通道
@EnableBinding(Sink.class)
public class Consumer {
    /**
     * 监控input通道,接收到的消息就是obj
     * @param obj 接收到的消息
     */
    @StreamListener(Sink.INPUT)
    public void getMsg(Object obj){
        System.out.println(obj);
    }
}

至此,消息消费者创建完毕
下面我们分别启动这三个模块,访问http://localhost:8013/sendMsg接口,向消息发送者发送消息,可以看到中转者和消费者分别打印出消息
在这里插入图片描述
在这里插入图片描述
如果我们有多个消息消费者,而消息每次只需要被消费一次该怎么办呢?

我们可以将多个消息消费者放到同一个组中,这样他们就会互相竞争,最终只有一个消费者会接收到消息。

bindings:
  input:
    destination: transfer-msg
    #多个消费者分到同一个组中会相互竞争
    group: group

自定义消息通道

在实际生产中,我们不可能仅仅使用stream提供的三个通道,这还远远不够,因此我们要自定义消息通道,其实很简单,就是比着葫芦画瓢。

首先我们来改stream-producer-8013,这是消息发送者,我们模拟一个myOutput通道

public interface MyOutput {
    String MYOUTPUT = "myOutput";

    //方法名是什么无所谓
    @Output("myOutput")
    MessageChannel output();
}

修改消息发送者,使用我们自定义的发送通道

//绑定输出通道
@EnableBinding(MyOutput.class)
public class Producer {
    @Autowired
    private MyOutput myOutput;

    public void sendMsg(User user){
        myOutput.output().send(MessageBuilder.withPayload(user).build());
    }
}

修改配置文件

spring:
  cloud:
    stream:
      bindings:
        myOutput: #绑定的通道,这里使用的是自定义的输出通道
          destination: msg #发送的目的地
          content-type: application/json #消息类型

接着我们修改stream-transfer-8014,这是消息中转者,我们来模拟一个MyTransfer通道

public interface MyTransfer {
    String MYOUTPUT = "myOutput";
    String MYINPUT = "myInput";

    @Output("myOutput")
    MessageChannel output();

    @Input("myInput")
    MessageChannel input();
}

修改消息中转者,使用我们自定义的中转通道

//绑定我们自定义的中转通道
@EnableBinding(MyTransfer.class)
public class Transfer {
    /**
     * 监控myInput通道,接收到的消息就是obj,最后发送加工过的消息到myOutput通道
     * @param obj 接收到的消息
     * @return 加工后的消息
     */
    @ServiceActivator(inputChannel = MyTransfer.MYINPUT, outputChannel = MyTransfer.MYOUTPUT)
    public Object getMsg(Object obj){
        //这里先将消息输出,再返回加工后的消息
        System.out.println(obj);
        return "经过中转者加工过的消息:"+obj;
    }
}

修改配置文件

spring:
  cloud:
    stream:
      bindings:
        myInput: #绑定的通道,这里使用的是我们自定义的输入通道
          destination: msg #从该目的地接受消息,上面消息发送者是向这个目的地发送消息
          content-type: application/json #消息类型
        myOutput: #绑定的通道,这里使用的是我们自定义的输出通道
          destination: transfer-msg #消息中转者等会向这个目的地发送消息
          content-type: application/json #消息类型

最后我们修改stream-consumer-8015,这是消息消费者,我们模拟一个MyInput通道

public interface MyInput {
    String MYINPUT = "myInput";

    @Input("myInput")
    MessageChannel input();
}

修改消息消费者,换成我们自定义的输入通道

//绑定我们自定义的输入通道
@EnableBinding(MyInput.class)
public class Consumer {
    /**
     * 监控myInput通道,接收到的消息就是obj
     * @param obj 接收到的消息
     */
    @StreamListener(MyInput.MYINPUT)
    public void getMsg(Object obj){
        System.out.println(obj);
    }
}

修改配置文件

spring:
  cloud:
    stream:
      bindings:
        myInput: #绑定的通道,这里使用的是自定义的输入通道
          destination: transfer-msg #从该目的地接受消息,上面消息中转者是向这个目的地发送消息
          content-type: application/json #消息类型

最后启动程序,访问http://localhost:8013/sendMsg接口,向消息发送者发送消息,可以看到中转者和消费者分别打印出消息
在这里插入图片描述
在这里插入图片描述

相关阅读

项目代码
SpringCloud 汇总【Greenwich 版】
SpringCloud(一):Eureka注册中心【Greenwich 版】
SpringCloud(二):Ribbon负载均衡【Greenwich 版】
SpringCloud(三):Feign声明式服务调用【Greenwich 版】
SpringCloud(四):Hystrix熔断器介绍【Greenwich 版】
SpringCloud(五):Hystrix的请求熔断与服务降级【Greenwich 版】
SpringCloud(六):Hystrix的请求合并【Greenwich 版】
SpringCloud(七):Hystrix仪表盘与Turbine集群监控【Greenwich 版】
SpringCloud(八):Zuul网关【Greenwich 版】
SpringCloud(九):Config配置中心【Greenwich 版】
SpringCloud(十):Bus消息总线【Greenwich 版】
SpringCloud(十一):Stream消息驱动 + RabbitMQ【Greenwich 版】
SpringCloud(十二):Sleuth链路跟踪【Greenwich 版】

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值