目录导航
前言
前面的章节我们讲了Spring Cloud Bus
本节,继续微服务专题的内容分享,共计16小节,分别是:
- 微服务专题01-Spring Application
- 微服务专题02-Spring Web MVC 视图技术
- 微服务专题03-REST
- 微服务专题04-Spring WebFlux 原理
- 微服务专题05-Spring WebFlux 运用
- 微服务专题06-云原生应用(Cloud Native Applications)
- 微服务专题07-Spring Cloud 配置管理
- 微服务专题08-Spring Cloud 服务发现
- 微服务专题09-Spring Cloud 负载均衡
- 微服务专题10-Spring Cloud 服务熔断
- 微服务专题11-Spring Cloud 服务调用
- 微服务专题12-Spring Cloud Gateway
- 微服务专题13-Spring Cloud Stream (上)
- 微服务专题14-Spring Cloud Bus
- 微服务专题15-Spring Cloud Stream 实现
- 微服务专题16-Spring Cloud 整体回顾
本节内容重点为:
- 实现 Spring Cloud Stream for RocketMQ
Spring Cloud Stream 以及 Binder 架构
参考 Spring Cloud Stream Binder 已有实现
这里我们参考 Spring Cloud Stream 文档:
Binder 实现步骤
A typical binder implementation consists of the following:
-
A class that implements the
Binder
interface;
实现Binder
接口 -
A Spring
@Configuration
class that creates a bean of typeBinder
along with the middleware connection infrastructure.
Binder
实现类上标注@Configuration
注解 -
A
META-INF/spring.binders
file found on the classpath containing one or more binder definitions, as shown in the following example:
META-INF/spring.binders
配置Binder
名称和Binder
实现自动装配类映射
kafka:\
org.springframework.cloud.stream.binder.kafka.config.KafkaBinderConfiguration
思考:假设有多个 Binder 实现 jar 同时存在,那么采用哪个呢?
- 配置默认 Binder 名称
spring.cloud.stream.defaultBinder = rabbit
- 指定某种 Binder 实现
spring.cloud.stream.bindings.input.binder=kafka
spring.cloud.stream.bindings.output.binder=rabbit
参考 Spring Cloud Stream Binder RabbitMQ
Spring Cloud Stream Binder RabbitMQ
参考 Spring Cloud Stream Binder Kafka
Spring Cloud Stream Binder Kafka
实现 Spring Cloud Stream Binder RocketMQ
我们仿造 Spring Cloud Stream Binder RabbitMQ与Spring Cloud Stream Binder Kafka的实现过程,开始实现Spring Cloud Stream Binder RocketMQ,一共分为三步:
-
RocketMQ -> 发消息、收消息
-
bindProducer 发消息
-
bindConsumer 收消息
预备工作
-
下载 RocketMQ
使用的是4.7.1版本,安装过程略 -
启动命名服务器
-
启动 MQ 代理
-
启动mq控制台(可有可无,主要为了演示作用)
实现步骤
- 创建
spring-cloud-stream-binder-rocketmq
工程
<groupId>com.test</groupId>
<artifactId>spring-cloud-stream-binder-rocketmq</artifactId>
<version>0.0.1-SNAPSHOT</version>
- 增加 Spring Cloud Stream Binder 依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream</artifactId>
</dependency>
- 增加 RocketMQ Client 依赖
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.3.0</version>
</dependency>
- 编写生产者demo
public class RocketMQProducerDemo {
public static void main(String[] args) throws Exception {
//Instantiate with a producer group name.
DefaultMQProducer producer = new
DefaultMQProducer("test-group");
//这里配置自己的mq地址即可
producer.setNamesrvAddr("127.0.0.1:9876");
//Launch the instance.
producer.start();
//CountDownLatch countDownLatch = new CountDownLatch(100);
//countDownLatch.await(10, TimeUnit.SECONDS);
for (int i = 0; i < 100; i++) {
//Create a message instance, specifying topic, tag and message body.
Message msg = new Message("TopicTest-1" /* Topic */,
"TagA" /* Tag */,
("Hello RocketMQ " +
i).getBytes(RemotingHelper.DEFAULT_CHARSET) /* Message body */
);
//Call send message to deliver message to one of brokers.
SendResult sendResult = producer.send(msg);
System.out.printf("%s%n", sendResult);
}
//Shut down once the producer instance is not longer in use.
producer.shutdown();
}
}
- 验证结果
启动mq后,并运行主函数
循环100次,这里显然运行成功!
- 编写消费者demo
public static void main(String[] args) throws Exception {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("test-group");
consumer.setNamesrvAddr("192.168.200.111:9876");
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
// //set to broadcast mode
// consumer.setMessageModel(MessageModel.BROADCASTING);
consumer.subscribe("TopicTest-1", "TagA");
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
ConsumeConcurrentlyContext context) {
System.out.printf(Thread.currentThread().getName() + " Receive New Messages: " + msgs + "%n");
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();
System.out.printf("Broadcast Consumer Started.%n");
}
}
- 验证结果
启动mq后,并运行主函数
循环100次,消费成功!
Spring Cloud Stream Binder For RocketMQ Starter
我们现在就编写一个功能通用的jar包:spring-cloud-stream-binder-rocketmq
,专门用以rocketmq与SpringCloud做绑定的一个服务。
首先我们实现RocketMQ的发消息:
public class RocketMQMessageChannelBinder implements
Binder<MessageChannel, ConsumerProperties, ProducerProperties> {
private static final String GROUP = "test-group";
private static final String TOPIC = "TEST_TOPIC";
private static final String TAG = "TEST_TAG";
private static final String NAME_ADDRESS = "192.168.200.111:9876";
@Override
public Binding<MessageChannel> bindConsumer(String name, String group,
MessageChannel inputChannel, ConsumerProperties consumerProperties) {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(GROUP);
consumer.setNamesrvAddr(NAME_ADDRESS);
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
try {
consumer.subscribe(TOPIC, TAG);
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
ConsumeConcurrentlyContext context) {
System.out.printf(Thread.currentThread().getName() + " Receive New Messages: " + msgs + "%n");
msgs.forEach(msg -> {
byte[] body = msg.getBody();
// 发送消息到 消息管道
inputChannel.send(new GenericMessage<Object>(body));
});
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();
} catch (Exception e) {
e.getMessage();
}
return () -> {
System.out.println("consumer shutdown...");
consumer.shutdown();
};
}
/**
* 发送消息
*
* @param name
* @param outputChannel
* @param producerProperties
* @return
*/
@Override
public Binding<MessageChannel> bindProducer(String name, MessageChannel outputChannel, ProducerProperties producerProperties) {
//Instantiate with a producer group name.
DefaultMQProducer producer = new DefaultMQProducer(GROUP);
producer.setNamesrvAddr(NAME_ADDRESS);
//Launch the instance.
try {
producer.start();
SubscribableChannel subscribableChannel = (SubscribableChannel) outputChannel;
// 消息订阅回调
subscribableChannel.subscribe(message -> {
// 消息主题
Object messageBody = message.getPayload();
Message mqMessage = new Message();
mqMessage.setTopic(TOPIC);
mqMessage.setTags(TAG);
try {
mqMessage.setBody(serialize(messageBody));
SendResult sendResult = producer.send(mqMessage);
System.out.printf("消息发送 : %s%n", sendResult);
} catch (Exception e) {
e.getMessage();
}
});
} catch (Exception e) {
e.printStackTrace();
}
return () -> {
System.out.println("producer shutdown...");
producer.shutdown();
};
}
private byte[] serialize(Object serializable) throws IOException {
if (serializable instanceof byte[]) {
return (byte[]) serializable;
}
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
// 通过 Java 序列化 将 Object 写入字节流
objectOutputStream.writeObject(serializable);
// 返回字节数组
return outputStream.toByteArray();
}
}
RocketMQMessageChannelBinderConfiguration配置:
@Configuration
public class RocketMQMessageChannelBinderConfiguration {
@Bean
public RocketMQMessageChannelBinder rocketMQMessageChannelBinder() {
return new RocketMQMessageChannelBinder();
}
}
加入配置文件实现自动装配类映射:
rocketmq=\
com.test.micro.services.spring.cloud.stream.binder.rocketmq.RocketMQMessageChannelBinderConfiguration
我们现在编写的jar包初步完成,可以称之为:spring-cloud-stream-binder-rocketmq (V1.0 版本),接下来我们如何测试呢?
在前面的章节我们多次提到了 spring-cloud-client-application 与 spring-cloud-server-application 两个服务,在此,同样地使用这两个模块集成spring-cloud-stream-binder-rocketmq (V1.0 版本):
- 客户端设置开放的api
@GetMapping("/stream/send/rocketmq")
public boolean streamSendToRocketMQ(@RequestParam String message) {
// 获取 MessageChannel
MessageChannel messageChannel = simpleMessageService.testChannel();
return messageChannel.send(new GenericMessage(message));
}
service实现:
public interface SimpleMessageService {
@Output("test007")
MessageChannel testChannel(); // destination = test007
}
- 客户端与服务端设置配置文件
spring.cloud.stream.defaultBinder = rabbit
## Spring Cloud Stream Binder - RocketMQ
### Channel 名字是 test007
spring.cloud.stream.bindings.test007.binder = rocketmq
spring.cloud.stream.bindings.test007.destination = test007
- 客户端pom引入spring-cloud-stream-binder-rocketmq 的jar包:
<!-- RocketMQ -->
<dependency>
<groupId>com.test</groupId>
<artifactId>spring-cloud-stream-binder-rocketmq</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
- 验证实现结果
首先启动zk与 spring-cloud-client-application 、 spring-cloud-server-application
然后访问地址:http://localhost:8888/stream/send/rocketmq?message=test
消息发送成功!
与此同时,服务端接收消息的情况是:
消息接收成功!
后记
本节代码地址:Spring Cloud Stream Binder For Rocketmq
更多架构知识,欢迎关注本套Java系列文章:Java架构师成长之路