Spring Cloud Stream是一个用于构建消息驱动的微服务应用程序的框架。Spring Cloud Stream构建于Spring Boot之上,用于创建独立的生产级Spring应用程序,并使用Spring Integration提供与消息代理的连接。也就是说,Spring Cloud Stream是构建于Spring Boot和Spring Integration之上的框架,帮助创建事件驱动或消息驱动的微服务。

主要模型如图:

这里我们使用Kafka作为消息底层设施,原因见: 为什么我们从RabbitMQ切换到apache kafka?

引入Kafka的Stream启动器:

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-stream-kafka</artifactId>
  <version>2.0.1.RELEASE</version>
</dependency>

微服务架构遵循“ 智能端点和哑管 ”原则,端点之间的通信由RabbitMQ或Apache Kafka等消息传递中间件方驱动,服务通过这些端点或通道发布领域事件进行通信。

首先我们定义一个接口,定义输入和输出队列管道:

public interface GreetingsStreams {
  String INPUT = "greetings-in";
  String OUTPUT = "greetings-out";
  @Input(INPUT)
  SubscribableChannel inboundGreetings();
  @Output(OUTPUT)
  MessageChannel outboundGreetings();
}

@Input注释用来表示输入的消息队列,通过该通道接收消息并输入当前应用;@Output注释表示一个输出通道,通过它发布消息出去。@Input和@Output注解可以采取指定的通道名称(比如这里greetings-in greetings-out")作为参数,如果未提供名称,则使用注释的方法名称。

在application.yaml或property中具体配置该消息通道到Kafka:

spring:
  cloud:
    stream:
      kafka:
        binder:
          brokers: localhost:9092
        bindings:
          greetings-in:
            destination: greetings
            contentType: application/json
          greetings-out:
            destination: greetings
            contentType: application/json

其中greetings-in和greetings-out配置到Kafka具体的主题topic名称为greetings,序列化类型是json,kafka默认端口在本地9092。

好了,底层基础设施准备完成,现在需要将这个设施安装到我们的应用中。

@EnableBinding(GreetingsStreams.class)
public class StreamsConfig {
}

@EnableBinding将应用配置绑定接口GreetingsStreams中定义的通道INPUT和OUTPUT。

现在我们的应用和消息基础设施已经绑定了,可使用@StreamListener到具体方法以接收具体的流处理事件了。

@Component
@Slf4j
public class GreetingsListener {
@StreamListener(GreetingsStreams.INPUT)
public void handleGreetings(@Payload Greetings greetings) {
  log.info("Received greetings: {}", greetings);
}
}

StreamListeners 是消息监听者处理方法,接收类型的传入消息Greetings,可以看到框架的核心功能之一:它尝试自动将传入的消息有效负载转换为类型Person。

上面方法是一个没有返回结果的void方法,如果有返回结果,必须使用@SendTo注释指定方法返回的数据的输出绑定队列目标output,如以下示例所示;通过

@Component
@Slf4j
public class GreetingsListener {
@StreamListener(GreetingsStreams.INPUT)
@SendTo(GreetingsStreams.OUTPUT)
public String handleGreetings(Greetings greetings) {
  log.info("Received greetings: {}", greetings);
  return "Received greetings: {}" + greetings;
}
}

Spring cloud stream实现了一个默认的Processor类,类似我们的GreetingsStreams接口,也就是说,可以不用自己做这个接口

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

如果使用默认的Processor通道名称,注意配置文件里也要配置成相应的通道名。

测试运行
有了接收方,下面我们实现一个发送方,我们通过调用rest接口发送消息,先看看发送方代码:

@Service
@Slf4j
public class GreetingsService {
private final GreetingsStreams greetingsStreams; public GreetingsService(GreetingsStreams greetingsStreams) {
  this.greetingsStreams = greetingsStreams;
} public void sendGreeting(final Greetings greetings) {
  log.info("Sending greetings {}", greetings);
  MessageChannel messageChannel = greetingsStreams.outboundGreetings();
  messageChannel.send(MessageBuilder
  .withPayload(greetings)
  .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON)
  .build());
}
}

我们暴露一个端口来调用这个发送方:

@RestController
public class GreetingsController {
private final GreetingsService greetingsService;
public GreetingsController(GreetingsService greetingsService) {
  this.greetingsService = greetingsService;
}
@GetMapping("/greetings")
@ResponseStatus(HttpStatus.ACCEPTED)
public void greetings(@RequestParam("message") String message) {
  Greetings greetings = Greetings.builder()
  .message(message)
  .timestamp(System.currentTimeMillis())
  .build();
  greetingsService.sendGreeting(greetings);
} }

也就是说:这个发送方REST和发送服务 与我们的GreetingsListener是通过消息系统通讯的,不是直接在发送服务里调用GreetingsListener的方法,这样这两者之间就解耦了。

下面我们用postman调用:

http://localhost:8080/greetings?message=hello

控制台结果输出:

c.e.c.GreetingsService : Sending greetings Greetings(timestamp=1535614400754, message=hello)

c.e.c.GreetingsListener : Received greetings: Greetings(timestamp=1535614400754, message=hello)

一个发送和一个接受完成了一个请求调用,如果GreetingsListener还有返回结果,是放在greetings-out之中的,那么GreetingsListener就变成发送方了,我们也可以参考这套做法再做个监听器。
---------------------

原文:https://blog.csdn.net/qq_42950313/article/details/82224660

SpringCloudStream实战的更多相关文章

  1. RabbitMQ与Spring的框架整合之Spring Cloud Stream实战

    1.RabbitMQ与Spring Cloud Stream整合实战.SpringCloud Stream整体结构核心概念图,如下所示: 图示解释:Outputs输出,即消息的发送端.Inputs输入 ...

  2. springCloud学习5(Spring-Cloud-Stream事件驱动)

    springcloud 总集:https://www.tapme.top/blog/detail/2019-02-28-11-33 代码见文章结尾   想想平常生活中做饭的场景,在用电饭锅做饭的同时, ...

  3. SSH实战 · 唯唯乐购项目(上)

    前台需求分析 一:用户模块 注册 前台JS校验 使用AJAX完成对用户名(邮箱)的异步校验 后台Struts2校验 验证码 发送激活邮件 将用户信息存入到数据库 激活 点击激活邮件中的链接完成激活 根 ...

  4. GitHub实战系列汇总篇

    基础: 1.GitHub实战系列~1.环境部署+创建第一个文件 2015-12-9 http://www.cnblogs.com/dunitian/p/5034624.html 2.GitHub实战系 ...

  5. MySQL 系列(四)主从复制、备份恢复方案生产环境实战

    第一篇:MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:MySQL 系列(二) 你不知道的数据库操作 第三篇:MySQL 系列(三)你不知道的 视图.触发器.存储过程.函数 ...

  6. Asp.Net Core 项目实战之权限管理系统(4) 依赖注入、仓储、服务的多项目分层实现

    0 Asp.Net Core 项目实战之权限管理系统(0) 无中生有 1 Asp.Net Core 项目实战之权限管理系统(1) 使用AdminLTE搭建前端 2 Asp.Net Core 项目实战之 ...

  7. 给缺少Python项目实战经验的人

    我们在学习过程中最容易犯的一个错误就是:看的多动手的少,特别是对于一些项目的开发学习就更少了! 没有一个完整的项目开发过程,是不会对整个开发流程以及理论知识有牢固的认知的,对于怎样将所学的理论知识应用 ...

  8. asp.net core 实战之 redis 负载均衡和"高可用"实现

    1.概述 分布式系统缓存已经变得不可或缺,本文主要阐述如何实现redis主从复制集群的负载均衡,以及 redis的"高可用"实现, 呵呵双引号的"高可用"并不是 ...

  9. Linux实战教学笔记08:Linux 文件的属性(上半部分)

    第八节 Linux 文件的属性(上半部分) 标签(空格分隔):Linux实战教学笔记 第1章 Linux中的文件 1.1 文件属性概述(ls -lhi) linux里一切皆文件 Linux系统中的文件 ...

随机推荐

  1. mybatis整合springboot 以及需要注意的细节

    具体怎么整合的网上有很多优秀的博客介绍,这里就直接引用一篇个人觉得非常详细的教程: https://blog.csdn.net/winter_chen001/article/details/77249 ...

  2. python中的协程

    目录 协程是啥 协程和线程差异 简单实现协程 greenlet 安装方式 gevent 安装 1. gevent的使用 2. gevent切换执行 3. 给程序打补丁 进程.线程.协程对比 请仔细理解 ...

  3. 学习HttpClient,从两个小例子开始

    前言 HTTP(Hyper-Text Transfer Protocol,超文本传输协议)在如今的互联网也许是最重要的协议,我们每天做的很多事情都与之有关,比如,网上购物.刷博客.看新闻等.偶尔你的上 ...

  4. 【Web前端】用CSS3实现弹幕

    初版 用css3来实现弹幕确实比较简单,只需要设置动画让弹幕从屏幕右侧移动到屏幕左侧即可,一开始是这样实现的 .danmu { position: fixed; left: %; animation: ...

  5. jQuery的一生

    jQuery 1.什么是jQuery? 是轻量级的,兼容多浏览器的JavaScript库,使用户能够方便的处理HTML Document,Events,实现动画效果,方便进行Ajax交互,能够极大地简 ...

  6. 对YUV数据进行裁剪

    项目中用到,用来对YUV数据(图片的yuv或者视频单帧yuv数据)进行裁剪. 格式介绍:http://blog.csdn.net/vblittleboy/article/details/1094514 ...

  7. 小程序实践(一):主页tab选项实现

    官方文档 效果图: 实现底部Tab选项,只需要在项目根目录下的app.json下修改 如图: ----------------------------------------------------- ...

  8. pyinstaller使用错误 SyntaxError: Non-UTF-8 code starting with '\xb4' in file C:......

    注:我的博客原本在CSDN,现转到博客园,图片采用以前的图片,并没有盗图.​​ 在将.py文件打包时,出现了下列错误 >>C:\Users\小呆\PycharmProjects\pycha ...

  9. python 画个小猪佩奇

    不知道大家小时候有没有学习过logo语言,就是操纵一只小王八,来画各种图案.博主小学微机课就学习了这个,最近发现python的turtle包就是logo语言,所以画个小猪佩奇和大家分享. 代码来自知乎 ...

  10. spark RDD,reduceByKey vs groupByKey

    Spark中有两个类似的api,分别是reduceByKey和groupByKey.这两个的功能类似,但底层实现却有些不同,那么为什么要这样设计呢?我们来从源码的角度分析一下. 先看两者的调用顺序(都 ...