pom文件
<dependencies>
<!-- 创建工程需要的两个依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- web 工程 -->
<dependency>
<groupId>com.imooc.ecommerce</groupId>
<artifactId>xyc-commerce-mvc-config</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
<version>2.5.0.RELEASE</version>
</dependency>
<!-- SpringCloud Stream-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream</artifactId>
</dependency>
<!-- SpringCloud Stream + Kafka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-kafka</artifactId>
</dependency>
<!-- SpringCloud Stream + RocketMQ -->
<!-- <dependency>-->
<!-- <groupId>com.alibaba.cloud</groupId>-->
<!-- <artifactId>spring-cloud-starter-stream-rocketmq</artifactId>-->
<!-- </dependency>-->
</dependencies>
<dependencyManagement>
<dependencies>
<!-- spring cloud 依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- spring cloud alibaba 依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
yml配置文件
server:
port: 8006
servlet:
context-path: /ecommerce-stream-client
spring:
application:
name: e-commerce-stream-client
cloud:
nacos:
# 服务注册发现
discovery:
enabled: true # 如果不想使用 Nacos 进行服务注册和发现, 设置为 false 即可
server-addr: 192.168.94.129:8848
namespace: d8fa475f-a1df-4cd3-acbf-e9d6df0ca59f
metadata:
management:
context-path: ${server.servlet.context-path}/actuator
# 消息驱动的配置
stream:
# SpringCloud Stream + Kafka
kafka:
binder:
brokers: 192.168.94.129:9092
auto-create-topics: true # 如果设置为false, 就不会自动创建Topic,
# 你在使用之前需要手动创建好
# SpringCloud Stream + RocketMQ
# rocketmq:
# binder:
# name-server: 127.0.0.1:9876
# 开启 stream 分区支持
instanceCount: 1 # 消费者的总数
instanceIndex: 0 # 当前消费者的索引
bindings:
# 默认发送方
output: # 这里用 Stream 给我们提供的默认 output 信道
destination: ecommerce-stream-client-default
# 消息发往的目的地, Kafka 中就是 Topic
content-type: text/plain # 消息发送的格式, 接收端不用指定格式, 但是发送端要
# 消息分区
producer:
# partitionKeyExpression: payload.author # 分区关键字,
#payload 指的是发送的对象, author 是对象中的属性
partitionCount: 1 # 分区大小
# 使用自定义的分区策略, 注释掉 partitionKeyExpression
partitionKeyExtractorName: qinyiPartitionKeyExtractorStrategy
partitionSelectorName: qinyiPartitionSelectorStrategy
# 默认接收方
input: # 这里用 Stream 给我们提供的默认 input 信道
destination: ecommerce-stream-client-default
group: e-commerce-qinyi-default
# 消费者开启分区支持
consumer:
partitioned: true
# Qinyi 发送方
qinyiOutput:
destination: ecommerce-stream-client-qinyi
content-type: text/plain
# Qinyi 接收方
qinyiInput:
destination: ecommerce-stream-client-qinyi
group: e-commerce-qinyi-qinyi
# spring-kafka 的配置
kafka:
bootstrap-servers: 192.168.94.129:9092
producer:
retries: 3
consumer:
auto-offset-reset: latest
# sleuth:
# sampler:
# # ProbabilityBasedSampler 抽样策略
# probability: 1.0 # 采样比例, 1.0 表示 100%, 默认是 0.1
# # RateLimitingSampler 抽样策略
# rate: 100 # 每秒间隔接受的 trace 量
# zipkin:
# sender:
# type: kafka # 默认是 http
# base-url: http://localhost:9411/
# 暴露端点
management:
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
show-details: always
消息的传递对象
@Data
@AllArgsConstructor
@NoArgsConstructor
public class QiyiMessage {
private Integer id;
private String projectName;
private String org;
private String author;
private String version;
/**
* 返回一个默认消息,方便使用
* @return
*/
public static QiyiMessage defaultMessage()
{
return new QiyiMessage(
1,
"e-commerce-stream-client",
"imooc-com",
"Qiyi",
"1.0"
);
}
}
自定义分区策略
/**
* ProjectName xyc-commerce-springcloud
* 从message中提取 partition key的策略
* @author xieyucan
* <br>CreateDate 2022/9/14 14:07
*/
@Slf4j
@Component
public class QinyiPartitionKeyExtractorStrategy implements PartitionKeyExtractorStrategy {
@Override
public Object extractKey(Message<?> message) {
QiyiMessage message1 = JSON.parseObject(message.getPayload().toString(), QiyiMessage.class);
String key = message1.getProjectName();
log.info("SpringCloud Stream QinYi partition Key:[{}]",key);
return key;
}
}
分区选择名称
/**
* ProjectName xyc-commerce-springcloud
* 决定message 或者 payload 发送到哪个分区的策略
* @author xieyucan
* <br>CreateDate 2022/9/14 14:07
*/
@Slf4j
@Component
public class QinyiPartitionSelectorStrategy implements PartitionSelectorStrategy {
/**
* 选择分区的策略
* @param key
* @param partitionCount
* @return
*/
@Override
public int selectPartition(Object key, int partitionCount) {
int partition=key.toString().hashCode()%partitionCount;
log.info("SpringCloud Stream QinYi Selector info:[{}],[{}],[{}]",
key.toString(),partitionCount,partition);
return partition;
}
}
默认发送方
@Slf4j
@EnableBinding(Source.class)
public class DefaultSendService {
private final Source source;
public DefaultSendService(Source source) {
this.source = source;
}
/**
* 使用默认的输出信道发送消息
* @param message
*/
public void sendMessage(QiyiMessage message)
{
String _message= JSON.toJSONString(message);
log.info("in DefaultSendService send message:[{}]",message);
//spring message,统一消息的编程模型,是stream组件的重要组成部分之一
source.output().send(MessageBuilder.withPayload(_message).build());
}
}
默认接收方
/**
* ProjectName xyc-commerce-springcloud
*
* @author xieyucan
* <br>CreateDate 2022/9/14 11:17
*/
@Slf4j
@EnableBinding(Sink.class)
public class DefaultReceiveService {
/**
* 使用默认的输入信道接收消息
* @param payload
*/
@StreamListener(Sink.INPUT)
public void receiveMessage(Object payload)
{
log.info("in DefaultReceiveService consume message start");
QiyiMessage message=JSON.parseObject(payload.toString(), QiyiMessage.class);
//消费消息
log.info("in DefaultReceiveService consume message success:[{}]",JSON.toJSONString(message));
}
}
自定义发送和接收
自定义输入信道
/**
* ProjectName xyc-commerce-springcloud
* 自定义输入信道
* @author xieyucan
* <br>CreateDate 2022/9/14 11:37
*/
public interface QinyiSink {
String INPUT="qinyiInput";
@Input(QinyiSink.INPUT)
SubscribableChannel qinyiInput();
}
自定义输出信道
/**
* ProjectName xyc-commerce-springcloud
* 自定义输出信道
* @author xieyucan
* <br>CreateDate 2022/9/14 11:28
*/
public interface QinyiSource {
String OUTPUT="qinyiOutput";
/**
* 输出信道的名称是 qinyiOutput,需要使用stream 绑定在yml文件中声明
* @return
*/
@Output(QinyiSource.OUTPUT)
MessageChannel qinyiOutput();
}
使用自定义的通信信道 QinyiSource 实现消息发送
/**
* ProjectName xyc-commerce-springcloud
* 使用自定义的通信信道 QinyiSource 实现消息发送
* @author xieyucan
* <br>CreateDate 2022/9/14 11:32
*/
@Slf4j
@EnableBinding(QinyiSource.class)
public class QinyiSendService {
private final QinyiSource qinyiSource;
public QinyiSendService(QinyiSource qinyiSource) {
this.qinyiSource = qinyiSource;
}
/**
* 使用自定义输出信道发送消息
* @param message
*/
public void sendMessage(QiyiMessage message)
{
String _message=JSON.toJSONString(message);
log.info("in QinyiSendService send message:[{}]",_message);
qinyiSource.qinyiOutput().send(MessageBuilder.withPayload(_message).build());
}
}
使用自定义的输入信道接收消息
/**
* ProjectName xyc-commerce-springcloud
* 使用自定义的输入信道接收消息
* @author xieyucan
* <br>CreateDate 2022/9/14 11:42
*/
@Slf4j
@EnableBinding(QinyiSink.class)
public class QinyiReceiveService {
/**
* 使用自定义的输入信道接收消息
* @param payload
*/
@StreamListener(QinyiSink.INPUT)
public void receiveMessage(@Payload Object payload)
{
log.info("in QinyiReceiveService consume message start");
QiyiMessage message = JSON.parseObject(payload.toString(), QiyiMessage.class);
log.info("in QinyiReceiveService consume message success:[{}]",JSON.toJSONString(message));
}
}