一 。 Spring Cloud Stream简介
Spring Cloud Stream 是一个构建消息驱动微服务的框架,应用程序通过 inputs通道 或者 outputs通道 来与 Spring Cloud Stream 中binder(kafka|rabbitmq) 交互,通过我们配置来 binding ,而 Spring Cloud Stream 的 binder 负责与中间件交互。
编程模型
Binder
Binder 是 Spring Cloud Stream 的一个抽象概念,是应用与消息中间件之间的粘合剂。
目前 Spring Cloud Stream 实现了 Kafka 和 Rabbit MQ 的binder。通过 binder ,可以很方便的连接中间件,可以动态的改变消息的destinations(对应于 Kafka 的topic,Rabbit MQ 的 exchanges),这些都可以通过外部配置项来做到。甚至可以任意的改变中间件的类型而不需要修改一行代码。
Publish-Subscribe
消息的发布(Publish)和订阅(Subscribe)是事件驱动的经典模式。Spring Cloud Stream 的数据交互也是基于这个思想。生产者把消息通过某个 topic 广播出去(Spring Cloud Stream 中的 destinations)。其他的微服务,通过订阅特定 topic 来获取广播出来的消息来触发业务的进行。
这种模式,极大的降低了生产者与消费者之间的耦合。即使有新的应用的引入,也不需要破坏当前系统的整体结构。
Consumer Groups
“Group”, Kafka 中的概念。Spring Cloud Stream 的这个分组概念的意思基本和 Kafka 一致。
微服务中动态的缩放同一个应用的数量以此来达到更高的处理能力是非常必须的。对于这种情况,同一个事件防止被重复消费,只要把这些应用放置于同一个 “group” 中,就能够保证消息只会被其中一个应用消费一次。
其他概念参考
http://cloud.spring.io/spring-cloud-static/Edgware.SR4/single/spring-cloud.html#_spring_cloud_stream
同时 springcloudstream是继承自spring框架spring-integration 其中概念百度 以下简单概要介绍
Message
Message是它的基础构件和核心,所有的流程都围绕着Message运转,如图所示
Message,就是所说的消息体,用来承载传输的信息用的。Message分为两部分,header和payload。header是头部信息,用来存储传输的一些特性属性参数。payload是用来装载数据的,他可以携带的任何Object对象 不同的对象在binder中传输 可以指定不同的mini类型 具体参考
http://cloud.spring.io/spring-cloud-static/Edgware.SR4/single/spring-cloud.html#contenttypemanagement
可以通过application.yml中设置 输入input和输出output的mini类型 spring.cloud.stream.bindings.
以下是所有支持的mini类型
Source Payload | Target Payload | content-type header (source message) |
content-type header (after conversion) |
Comments |
---|---|---|---|---|
POJO |
JSON String |
ignored |
application/json |
|
Tuple |
JSON String |
ignored |
application/json |
JSON is tailored for Tuple |
POJO |
String (toString()) |
ignored |
text/plain, java.lang.String |
|
POJO |
byte[] (java.io serialized) |
ignored |
application/x-java-serialized-object |
|
JSON byte[] or String |
POJO |
application/json (or none) |
application/x-java-object |
|
byte[] or String |
Serializable |
application/x-java-serialized-object |
application/x-java-object |
|
JSON byte[] or String |
Tuple |
application/json (or none) |
application/x-spring-tuple |
|
byte[] |
String |
any |
text/plain, java.lang.String |
will apply any Charset specified in the content-type header |
String |
byte[] |
any |
application/octet-stream |
will apply any Charset specified in the content-type header |
MessageChannel
消息管道,生产者生产一个消息到channel,消费者从channel消费一个消息,所以channel可以对消息组件解耦,并且提供一个方便的拦截功能和监控功能。
默认的通道
输入(SubscribableChannel)和输出通道(MessageChannel)参考 Processor接口
springcloudstream提供通道的定义 比如自定义通过可以使用接口
public interface OrderChannel {
String INPUT = "input_order";
String OUTPUT="ouput_order";
/**
* input注解制定通道的名称 将来在yml中配置该通道的实际绑定的topic或者订阅组
* @return
*/
@Input(INPUT)
SubscribableChannel orderInput();
/**
* output注解指定输出通道的名称
* @return
*/
@Output(OUTPUT)
MessageChannel orderOutput();
}
以下 代码参考 Source Sink Processor接口 将来在yml关于该通道的配置既可以
spring:
cloud:
stream:
bindings:
通道名称:
destination: mydest
二。Spring Cloud Stream入门案例
1》安装kafka
具体kafaka学习参考https://blog.csdn.net/liaomin416100569/article/details/78799488
下载kafka:
https://www.apache.org/dyn/closer.cgi?path=/kafka/1.1.1/kafka_2.11-1.1.1.tgz
解压 将kafka_2.11-1.1.1\bin\windows 目录添加到PATH环境变量中
bin目录下 新建文件 runzk.cmd 内容
pushd %~dp0
zookeeper-server-start.bat ../../config/zookeeper.properties
新建 runkafka.cmd 内容
pushd %~dp0
kafka-server-start.bat ../../config/server.properties
运行 runzk.cmd 然后运行 runkafka.cmd
插件 mydest的主题
kafka-topics --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic mydest
订阅主题 在控制台等消息
kafka-console-producer --broker-list localhost:9092 --topic mydest
给主题发送消息 测试
kafka-console-producer.sh --broker-list localhost:9092 --topic mydest
2》helloworld案例
以下helloworld程序 参考自官网
http://cloud.spring.io/spring-cloud-static/Edgware.SR4/single/spring-cloud.html#_getting_started
添加订阅监听消息的maven项目 添加依赖
org.springframework.boot
spring-boot-starter-parent
1.5.13.RELEASE
org.springframework.cloud
spring-cloud-dependencies
Dalston.SR5
pom
import
org.springframework.cloud
spring-cloud-stream-binder-kafka
yml中设置 订阅者 input通道的消息重点的主题 (topic) 这里同时设置 kafka的broker 还有zookeeper默认是本机所以不用设置
参考http://cloud.spring.io/spring-cloud-static/Edgware.SR4/single/spring-cloud.html#_apache_kafka_binder
37.31章节 比如
spring.cloud.stream.kafka.binder.brokers 设置 broker的ip和端口 默认是localhost:9092
spring.cloud.stream.kafka.binder.zkNodes 设置zk集群的ip 默认是localhost
spring.cloud.stream.kafka.binder.defaultZkPort 设置默认的zk端口 默认是 2181
server:
port: 8088
spring:
cloud:
stream:
bindings:
input:
destination: mydest
添加一个消息绑定的运行主类
package cn.ps.stream.input;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.cloud.stream.messaging.Sink;
import org.springframework.messaging.Message;
@SpringBootApplication
/**
* @EnableBinding表示啟動綁定到中間件 該注解中制定的接口可以定義不同的通道
* 默認
* Sink 存在一個名字是input的輸入通過
* Source 存在一個名字是output額輸出通道
* Processor繼承Sink和Source 擁有兩個通道
* @author Administrator
*
*/
@EnableBinding(Sink.class)
public class InputMain {
/**
* 監聽輸入通道的消息 消息會傳送到 方法的入参
* Payload是消息体
* header是消息头
* @param message
*/
@StreamListener(Sink.INPUT)
public void receive(Message message) {
System.out.println(message.getPayload());
}
public static void main(String[] args) {
SpringApplication sa=new SpringApplication(InputMain.class);
sa.run(args);
}
}
添加轮询(每秒发送一次)发送消息的maven项目 添加依赖
同上maven依赖
application.yml设置输出通道的目的 topic
server:
port: 8089
spring:
cloud:
stream:
bindings:
output:
destination: mydest
添加轮询的main方法测试
package cn.ps.stream.output;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.context.annotation.PropertySource;
import org.springframework.integration.annotation.InboundChannelAdapter;
@SpringBootApplication
@EnableBinding(Source.class)
public class OutputMain {
@InboundChannelAdapter(Source.OUTPUT)
public String greet() {
return "hello world " + System.currentTimeMillis();
}
public static void main(String[] args) {
SpringApplication sa = new SpringApplication(OutputMain.class);
sa.run(args);
}
}
发现input的项目的控制台 不停地接受到消息
其他的比如自定义 通道的接口 等 参考编程模型
http://cloud.spring.io/spring-cloud-static/Edgware.SR4/single/spring-cloud.html#_programming_model