介绍
通过stream可以让程序跟具体队列组件解耦,程序不用关心队列组件的使用,只要建立好相应的通道,不论队列组件怎么更换,程序都无需关心。stream让程序通过通道来进行消息的生产和消费。
Stream中的input和output只是个别名,不论生产者的输出通道名和消费者的输入通道名叫什么都无所谓,真正实现效果的是通道绑定了哪个交换机哪个队列。
对于通道的命名,为了易于区分,可让输入和输出采用同样的通道名,表示生产者往这个通道发送消息,消费者消费消息;或者采用channel_output和channel_input的写法,用于区分输入和输出方。
在springboot2.x以上对应的springcloud stream版本中,在同个项目中将相同的通道名绑定到不同通道可能会报该通道名已存在的错误。在看过的教程里,作者的版本是2.0.0.M3,springcloud是Finchley.M2可以将同样的通道名绑定到不同的通道上(纳闷)。
如下图所示,input代表消费者,交换机和队列是由消费者创建。该配置表示将交换机wdtest_下的average队列绑定到通道input(命名随意别重复即可)。在写程序时只需监听该通道即可接收到该队列的消息。
扫描二维码关注公众号,回复:
3907483 查看本文章
output代表生产者,该配置表示将交换机绑定到该通道下,程序只需往该通道发送消息即可。
搭建
springboot和springcloud的版本:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<spring-cloud.version>Finchley.SR1</spring-cloud.version>
</properties>
消费者配置
定义通道名:
package com.sosmmh.product.message;
import org.springframework.cloud.stream.annotation.Input;
import org.springframework.messaging.SubscribableChannel;
import org.springframework.stereotype.Component;
/**
* @author Lixh
* @Date: 2018/8/29 14:16
* @Description:
*/
@Component
public interface CustomSink {
String INPUT = "input3";
String INPUT0 = "input0";
String INPUT1 = "input1";
String INPUT2 = "input2";
@Input(INPUT)
SubscribableChannel input();
@Input(INPUT0)
SubscribableChannel input0();
@Input(INPUT1)
SubscribableChannel input1();
@Input(INPUT2)
SubscribableChannel input2();
}
监听通道:
package com.sosmmh.product.message;
import com.sosmmh.product.dto.CartDTO;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.messaging.support.GenericMessage;
/**
* @author Lixh
* @Date: 2018/8/29 14:16
* @Description:
*/
@EnableBinding({ CustomSink.class })
public class Consumer {
@StreamListener(CustomSink.INPUT)
public synchronized void listen_average(CartDTO cartDTO) {
System.out.println("Order Received For Average : " + cartDTO);
}
@StreamListener(CustomSink.INPUT0)
public synchronized void listen_hdfsWrite(CartDTO cartDTO) {
System.out.println("Order Received For hdfsWrite : " + cartDTO);
}
@StreamListener(CustomSink.INPUT1)
public synchronized void receive(CartDTO cartDTO) {
System.out.println("Item Received: " + cartDTO);
}
@StreamListener(CustomSink.INPUT2)
public synchronized <T> void get(GenericMessage<T> msg) {
System.out.println("Msg Received: " + msg.getPayload());
}
}
配置文件:这里使用了通用配置的rabbitmq
spring:
cloud:
stream:
bindings:
input:
destination: wdtest_
content-type: application/json
group: average
input3:
destination: wdtest0
content-type: application/json
group: average
input0:
destination: wdtest0
content-type: application/json
group: hdfsWrite
input1:
destination: wdtest1
content-type: application/json
group: average
input2:
destination: wdtest2
content-type: application/json
group: average
input11:
destination: wdtest11
content-type: application/json
group: average
input22:
destination: wdtest22
content-type: application/json
group: average
rabbitmq:
host: 192.168.61.150
port: 5672
username: guest
password: guest
生产者配置
定义通道名:
package com.sosmmh.order.message;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.MessageChannel;
import org.springframework.stereotype.Component;
/**
* @author Lixh
* @Date: 2018/8/29 14:12
* @Description:
*/
@Component
public interface CustomSource {
String OUTPUT = "output3";
String OUTPUT1 = "output1";
String OUTPUT2 = "output2";
@Output(OUTPUT)
MessageChannel output();
@Output(OUTPUT1)
MessageChannel output1();
@Output(OUTPUT2)
MessageChannel output2();
}
发送消息:
package com.sosmmh.order.message;
import com.sosmmh.order.dto.CartDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* @author Lixh
* @Date: 2018/8/29 14:13
* @Description:
*/
@EnableBinding({ CustomSource.class })
@Component
public class Producer {
@Autowired
private CustomSource source;
@Scheduled(fixedRate = 5000)
public void produceHotDrinks() {
source.output().send(
MessageBuilder.withPayload(new CartDTO("produceHotDrinks", 1)).build());
}
@Scheduled(fixedRate = 3000)
public void produceColdDrinks() {
source.output().send(MessageBuilder
.withPayload(new CartDTO("produceColdDrinks", 2)).build());
}
@Scheduled(fixedRate = 3000)
public void produceItem() {
source.output1()
.send(MessageBuilder.withPayload(new CartDTO("produceItem", 3)).build());
}
@Scheduled(fixedRate = 3000)
public void produceMsg() {
source.output2().send(MessageBuilder.withPayload("produceMsg").build());
}
}
配置文件:
spring:
cloud:
stream:
bindings:
output:
destination: wdtest_
content-type: application/json
output3:
destination: wdtest0
content-type: application/json
output1:
destination: wdtest1
content-type: application/json
output2:
destination: wdtest2
content-type: application/json
output11:
destination: wdtest11
content-type: application/json
output22:
destination: wdtest22
content-type: application/json
rabbitmq:
host: 192.168.61.150
port: 5672
username: guest
password: guest