Spring Cloud Stream 是一个构建消息驱动微服务的框架,该框架在Spring Boot的基础上整合了Spring Integrationg来连接消息代理中间件(RabbitMQ, Kafka等),提供了个性化的自动化配置实现,并引入了发布-订阅、消费组、分区这三个核心概念。
应用程序通过input通道或者output通道来与Spring Cloud Stream中binder(绑定器)交互,通过配置来binding. 而Spring Cloud Stream的binder负责与中间件交互。

开发工具:IntelliJ IDEA 2019.2.3

一、服务器端

1、创建项目

IDEA中创建一个新的SpringBoot项目,名称为“spring-server”,SpringBoot版本选择2.1.10,在选择Dependencies(依赖)的界面勾选Spring Cloud Discovery -> Eureka Server。
pom.xml完整内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.10.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>spring-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-server</name>
<description>Demo project for Spring Boot</description> <properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR4</spring-cloud.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies> <dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>

2、修改配置application.yml

修改端口号为8761;取消将自己信息注册到Eureka服务器,不从Eureka服务器抓取注册信息。

server:
port: 8761
eureka:
client:
register-with-eureka: false
fetch-registry: false

3、修改启动类代码

增加注解@EnableEurekaServer

package com.example.springserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication
@EnableEurekaServer
public class SpringServerApplication { public static void main(String[] args) {
SpringApplication.run(SpringServerApplication.class, args);
} }

二、消息生产者

1、创建项目
IDEA中创建一个新的SpringBoot项目,名称为“spring-producer”,SpringBoot版本选择2.1.10,在选择Dependencies(依赖)的界面勾选Web -> Spring Web,Spring Cloud Discovery -> Eureka Discovery Client。
打开pom.xml,添加依赖spring-cloud-starter-stream-rabbit,会自动引入spring-cloud-stream和spring-cloud-stream-binder。
pom.xml完整内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.10.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>spring-producer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-producer</name>
<description>Demo project for Spring Boot</description> <properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR4</spring-cloud.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-test-support</artifactId>
<scope>test</scope>
</dependency>
</dependencies> <dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>

2、修改配置application.yml

pom.xml使用RabbitMQ,默认情况下,连接本地的5672端口。下面这段rabbitmq也可省略。

server:
port: 8081
spring:
application:
name: spring-producer
eureka:
instance:
hostname: localhost
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
rabbitmq:
host: localhost
post: 5672
username: guest
password: guest

3、编写发送服务

方法sendOrder使用@Output("myInput")注解表示创建myInput的消息通道。调用该方法后,会向myInput通道投递消息。
如果不使用参数myInput,则使用方法名作为通道名称。

package com.example.springproducer;

import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.SubscribableChannel; public interface SendService {
@Output("myInput")
SubscribableChannel sendOrder();
}

4、修改启动类代码

加入注解@EnableBinding以开启Spring容器的绑定功能,以SendService.class为参数,Spring容器启动时,会自动绑定SendService接口中定义的通道。

package com.example.springproducer;

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; @SpringBootApplication
@EnableEurekaClient
@EnableBinding(SendService.class)
public class SpringProducerApplication { public static void main(String[] args) {
SpringApplication.run(SpringProducerApplication.class, args);
} }

5、添加一个控制器类

调用SendService的发送方法,往服务器发送消息。

package com.example.springproducer;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController; @RestController
public class ProducerController { @Autowired
SendService sendService; @RequestMapping(value="/send",method= RequestMethod.GET)
public String sendRequest(){
//创建消息
Message msg = MessageBuilder.withPayload("hello world".getBytes()).build();
//发送消息
sendService.sendOrder().send(msg);
return "SUCCESS";
}
}

三、消息消费者

1、创建项目

IDEA中创建一个新的SpringBoot项目,名称为“spring-consumer”,SpringBoot版本选择2.1.10,在选择Dependencies(依赖)的界面勾选Web -> Spring Web,Spring Cloud Discovery -> Eureka Discovery Client。
打开pom.xml,添加依赖spring-cloud-starter-stream-rabbit

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.10.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>spring-consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-consumer</name>
<description>Demo project for Spring Boot</description> <properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR4</spring-cloud.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency> <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies> <dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>

2、修改配置application.yml

server:
port: 8080
spring:
application:
name: spring-consumer
eureka:
instance:
hostname: localhost
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
rabbitmq:
host: localhost
post: 5672
username: guest
password: guest

3、缩写接受消息的通道接口

package com.example.springconsumer;

import org.springframework.cloud.stream.annotation.Input;
import org.springframework.messaging.SubscribableChannel; public interface ReceiveService {
@Input("myInput")
SubscribableChannel myInput();
}

4、修改启动类代码

同样绑定消息通道

package com.example.springconsumer;

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; @SpringBootApplication
@EnableBinding(ReceiveService.class)
public class SpringConsumerApplication { public static void main(String[] args) {
SpringApplication.run(SpringConsumerApplication.class, args);
} //订阅myInput通道的消息
@StreamListener("myInput")
public void receive(byte[] msg){
System.out.println("接收到的消息:" + new String(msg));
}
}

5、测试

(1)检查服务里面的RabbitMQ是否有启动(默认启动);

(2)启动spring-server(8761端口);

(3)启动spring-producer(8081端口);

(4)启动spring-consumer(8080端口);

(5)浏览器访问http://localhost:8081/send,spring-consumer项目的控制台输出:

接收到的消息:hello world

说明消费者已经可以从消息代理中获取到消息。

四、更换绑定器

上面使用了RabbitMQ作为消息代理,如果使用Kafka,可以更换Maven依赖实现。
在生产者和消费者的pom.xml中,将spring-cloud-starter-stream-rabbit修改为spring-cloud-starter-stream-kafka。

五、Sink、Source与Processor接口

为了简化开发,Spring Cloud Stream内置了3个接口:Sink、Source与Processor。接口定义如下:

public interface Source {
String OUTPUT = "output"; @Output("output")
MessageChannel output();
}
public interface Sink {
String INPUT = "input"; @Input("input")
SubscribableChannel input();
}
public interface Processor extends Source, Sink {
}

通过上面内置接口,不必编写服务接口,生产者绑定通道时加入Source.class,消费者绑定通道时加入Sink.class,因为Processor继承于Sink与Source,也可以只使用Processor。

1、消息生产者代码改写如下:

(1)启动类代码

绑定通道时加入Processor.class

package com.example.springproducer;

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;
import org.springframework.cloud.stream.messaging.Processor; @SpringBootApplication
@EnableEurekaClient
@EnableBinding(Processor.class)
public class SpringProducerApplication { public static void main(String[] args) {
SpringApplication.run(SpringProducerApplication.class, args);
} }

(2)修改配置application.yml

绑定名为input的消息队列,否则消息队列默认为output。

server:
port: 8081
spring:
application:
name: spring-producer
cloud:
stream:
bindings:
output:
destination: input
eureka:
instance:
hostname: localhost
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/

(3)删除服务接口SendService

2、消息消费者代码改写如下:

(1)启动类代码

绑定通道时加入Processor.class

package com.example.springconsumer;

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.Processor;
import org.springframework.messaging.handler.annotation.SendTo; @SpringBootApplication
@EnableBinding(Processor.class)
public class SpringConsumerApplication { public static void main(String[] args) {
SpringApplication.run(SpringConsumerApplication.class, args);
} @StreamListener(Processor.INPUT)
public void receive(byte[] msg){
System.out.println("接收到的消息:" + new String(msg));
}
}

(2)删除服务接口ReceiveService

重新启动应用,浏览器访问http://localhost:8081/send,spring-consumer项目的控制台输出:

接收到的消息:hello world

、消费者组

消费者组不同时,会发送给所有的消费者实例。
消费者组相同时,对于发送过来的消息,仅由其中一个消费者实例处理。

1、修改消费者spring-consumer项目的配置application.yml,配置消费者组为groupA

server:
port: 8080
spring:
application:
name: spring-consumer
cloud:
stream:
bindings:
input:
group:
groupA
eureka:
instance:
hostname: localhost
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/

2、仿照上面消费者spring-consumer项目,新建两个消费者项目spring-second-consumer(端口8082)和spring-third-consumer(端口8083),配置application.yml的消费者组都为groupB。

重新启动应用,浏览器多次访问http://localhost:8081/send,可以看到原来消费者spring-consumer都能收到,新加的两个消费者spring-second-consumer(端口8082)和spring-third-consumer(端口8083)会轮询处理。

SpringCloud之Spring Cloud Stream:消息驱动的更多相关文章

  1. spring cloud 2.x版本 Spring Cloud Stream消息驱动组件基础教程(kafaka篇)

    本文采用Spring cloud本文为2.1.8RELEASE,version=Greenwich.SR3 本文基于前两篇文章eureka-server.eureka-client.eureka-ri ...

  2. Spring Cloud Stream消息驱动之RocketMQ入门(一)

    SpringCloudStream目前支持的中间件有RabbitMQ.Kafka,还有我最近在学习的RocketMQ,以下是我学习的笔记 学习Spring cloud Stream 可以先学习一下了解 ...

  3. Spring Cloud Stream消息驱动@SendTo和消息降级

    参考程序员DD大佬的文章,自己新建demo学习学习,由于需要消息回执,看到了@SendTo这个注解能够实现,下面开始学习demo,新建两个项目cloud-stream-consumer消费端 和 cl ...

  4. Spring Cloud Stream消息总线

    Springcloud 里面对于MQ的整合一个是前一篇的消息总线一个是本文介绍的消息驱动 大体要学习这么几个知识点: 课题:SpringCloud消息驱动Stream1.什么是SpringCloud消 ...

  5. SpringCloud(七)Stream消息驱动

    Stream消息驱动 概述 屏蔽底层消息中间件的差异,降低切换成本,统一消息的编程模型 官网:https://cloud.spring.io/spring-cloud-static/spring-cl ...

  6. 「 从0到1学习微服务SpringCloud 」08 构建消息驱动微服务的框架 Spring Cloud Stream

    系列文章(更新ing): 「 从0到1学习微服务SpringCloud 」01 一起来学呀! 「 从0到1学习微服务SpringCloud 」02 Eureka服务注册与发现 「 从0到1学习微服务S ...

  7. 第十章 消息驱动的微服务: Spring Cloud Stream

    Spring Cloud Stream 是一个用来为微服务应用构建消息驱动能力的框架. 它可以基于Spring Boot 来创建独立的. 可用于生产的 Spring 应用程序. 它通过使用 Sprin ...

  8. 使用 Spring Cloud Stream 构建消息驱动微服务

    相关源码: spring cloud demo 微服务的目的: 松耦合 事件驱动的优势:高度解耦 Spring Cloud Stream 的几个概念 Spring Cloud Stream is a ...

  9. 消息驱动式微服务:Spring Cloud Stream & RabbitMQ

    1. 概述 在本文中,我们将向您介绍Spring Cloud Stream,这是一个用于构建消息驱动的微服务应用程序的框架,这些应用程序由一个常见的消息传递代理(如RabbitMQ.Apache Ka ...

随机推荐

  1. JVM(2)--深入理解java对象创建始终

    java对象探秘 java是一门面向对象的语言,我们无时无刻不在创建对象和使用对象,那么java虚拟机是如何创建对象的?又是如何访问对象的?java对象中究竟存储了什么运行时所必需的数据?在学习了ja ...

  2. golang实现rabbitmq消息队列失败尝试

    在工作中发现,有些时候消息因为某些原因在消费一次后,如果消息失败,这时候不ack,消息就回一直重回队列首部,造成消息拥堵. 如是有了如下思路: 消息进入队列前,header默认有参数 retry_nu ...

  3. c 程序之 最大公约数 和 最小公倍数

    1.最大公约数     30  10  -> 10 #include<stdio.h> /* 求最大公约数 辗转相减法 36 --16 4 */ int main(){ int a, ...

  4. 把Git Repository建到U盘上去

    Git很火.原因有三: 它是大神Linus Torvalds的作品,天然地具备神二代的气质和品质: 促进了生产力的发展,Git的分布式版本控制理念,并非首创,但非常适合开源社区的协作方式(不存在mas ...

  5. CMSdede后台登陆界面设计

    1 在这里我就公布 css 和jq  也就是dede文件下templets的login.htm页面:代码如下      $(function () {             $(".tex ...

  6. .Net Core3.1下使用Swagger搭建web api项目

    前言:微软于前天发布.net core 3.1正式版,并将长期支持3.1.所以我听到这个消息后就急忙下载.net core 3.1的SDK和Runtime,应该是公司最先用3.1的攻城狮了

  7. 解决Connection to Xxx@localhost failed.

    解决: Connection to jianshu@localhost failed. [08001] Could not create connection to database server. ...

  8. 数据结构与算法之java语言实现(一):稀疏数组

    一.概念&引入 什么是稀疏数组? 稀疏数组是面对一个二维数组中有众多重复元素的情况下,为了节省磁盘空间,将此二维数组转化为更加节省空间的一种数组,我们叫他稀疏数组. 只是听概念或许会看不明白, ...

  9. C#语法--委托,架构的血液

    委托的定义 什么是委托? 委托实际上是一种类型,是一种引用类型. 微软用delegate关键字来声明委托,delegate与int,string,double等关键字一样.都是声明用的. 下面先看下声 ...

  10. 求亿级记录中搜索次数Top N的搜索词(MapReduce实现)

    程序事例: 日志信息: 二手车 1345 二手房 3416 洗衣机 2789 输入: N=2 输出: 二手房 洗衣机 map函数如下: import java.io.IOException; impo ...