spring boot版本:2.1.10.RELEASE
spring cloud版本:Greenwich.SR4
上一篇博文 Spring Cloud Stream 初步了解了Spring Cloud Stream,并写了一个入门的例子,本文在上一篇的基础上,实现消息的分组和消息的分区。
stream-receiver 项目
(1)添加配置
#配置eureka注册中心
eureka.client.service-url.defaultZone=http://192.168.xxx.xxx:8761/eureka/,http://192.168.xxx.xxx:8762/eureka/
eureka.instance.prefer-ip-address=true
#rabbitmq配置
spring.rabbitmq.host=192.168.xxx.xxx
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=admin
spring.rabbitmq.virtual-host=/
# 对应 MQ 是 exchange
# 其中 inputProduct 是可变的, IReceiveService@Input注解中的值
# exchangeProduct是rabbitmq中交换器的名, 发送者和接收者需一致
spring.cloud.stream.bindings.inputProduct.destination=exchangeProduct
# 具体分组 对应 MQ 是 队列名称 并且持久化队列
spring.cloud.stream.bindings.inputProduct.group=groupProduct
(2)接收类接口
package com.ebook.stream;
import org.springframework.cloud.stream.annotation.Input;
import org.springframework.messaging.SubscribableChannel;
/**
* @author:JZ
* @date:2020/2/2
*/
public interface IReceiveService {
String INPUT = "inputProduct";
@Input(INPUT)
SubscribableChannel receive();
}
(3)接收类接口的实现类
package com.ebook.stream;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.stereotype.Service;
/**
* @author:JZ
* @date:2020/2/2
*/
@Service
@EnableBinding({IReceiveService.class})
public class ReceiveService {
//Product为自定义实体类
@StreamListener(IReceiveService.INPUT)
public void onReceive(Product product) {
System.out.println("receive:" + product.toString());
}
}
stream-sender 项目
(1)添加配置
#配置eureka注册中心
eureka.client.service-url.defaultZone=http://192.168.xxx.xxx:8761/eureka/,http://192.168.xxx.xxx:8762/eureka/
eureka.instance.prefer-ip-address=true
#rabbitmq配置
spring.rabbitmq.host=192.168.xxx.xxx
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=admin
spring.rabbitmq.virtual-host=/
# 对应 MQ 是 exchange,
# 其中 outputProduct 是可变的, 其对应的值是ISendService类中@Output注解中的值
# exchangeProduct是rabbitmq中交换器的名, 发送者和接收者需一致
spring.cloud.stream.bindings.outputProduct.destination=exchangeProduct
(2)发送接口
package com.ebook.stream;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.SubscribableChannel;
/**
* @author:JZ
* @date:2020/2/2
*/
public interface ISendService {
String OUTPUT = "outputProduct";
@Output(OUTPUT)
SubscribableChannel send();
}
(3)在启动类中添加注解
package com.ebook.stream;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.stream.annotation.EnableBinding;
/**
* @author:JZo
* @date:2020/1/11
*/
@SpringBootApplication
@EnableEurekaClient
@EnableBinding({ISendService.class})//注册成bean
public class StreamSenderApplication {
public static void main(String[] args) {
SpringApplication.run(StreamSenderApplication.class, args);
}
}
(4)运行测试类,发送消息
import com.ebook.stream.ISendService;
import com.ebook.stream.Product;
import com.ebook.stream.StreamGroupSender;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = StreamGroupSender.class)
public class StreamTest {
@Autowired
private ISendService send;
@Test
public void send() throws InterruptedException {
//Product为自定义实体类
Product product = new Product(1, "Spring Cloud");
Message message = MessageBuilder.withPayload(product).build();
this.send.send().send(message);
}
}
消息分区
通过以上配置可实现相同服务集群配置时,会将相同的消息均匀地发送到各个服务上。例如有10条相同的消息,集群中有2个服务,那么每个服务会接收到5条消息。
如果想要相同消息在集群中被同一个服务消费那么可以添加如下配置。
在接收者服务中添加
#开启消费者分区功能
spring.cloud.stream.bindings.inputProduct.consumer.partitioned=true
#指定了当前消费者的总实例数量(集群中服务的数量)
spring.cloud.stream.instanceCount=2
#设置当前实例的索引号,从0开始
spring.cloud.stream.instanceIndex=0
在发送者服务中添加
#通过该参数指定了分区键的正则表达式规则
spring.cloud.stream.bindings.outputProduct.producer.partitionKeyExpression=payload
#指定了消息分区的数量。
spring.cloud.stream.bindings.outputProduct.producer.partitionCount=2