RSocket 入门:Spring Boot 服务器

工程 | Ben Wilcock | 2020年3月2日 | ...

时间:大约 15 分钟。

在多样化的微服务世界中,HTTP 是代理间通信的无可争议的领导者。它成熟、完善且无处不在。但在某些情况下,HTTP 请求-响应可能很繁琐。如果您需要超越传统请求-响应的通信模式,例如即发即弃或流式传输怎么办?如果您想双向发送消息怎么办?

使用 HTTP,有一些方法可以实现这一点,但这并非该协议的构建目的。许多解决方案都伴随着额外的权衡或缺点。此外,没有规定说“你应该始终使用 HTTP”,像 AMQP 这样的消息协议已经证明了这一点。因此,了解您的选择很重要,并且偶尔向您的列表中添加一些新技术也很有益。这篇文章就是关于这样一个替代方案——RSocket。

RSocket 是一种新的消息协议,旨在解决一些常见的微服务通信挑战。使用 RSocket,您可以获得一个灵活的协议,该协议可在 TCP 或 WebSockets 上运行。这意味着您可以进行二进制消息而无需转换。您可以获得诸如多路复用、背压、恢复和路由之类的现代控制,并且您可以获得多种消息模式,包括即发即弃、请求-响应和流式传输。RSocket 也是完全响应式的,因此非常适合您的高吞吐量微服务应用程序。早期采用者包括 Netflix、Pivotal、阿里巴巴和 Facebook——它们都是提供可扩展的基于互联网的服务的专家。

在这篇文章中——这是本系列的第一篇文章——您将学习如何开始使用 RSocket。您将熟悉它的工作原理,并体验它的一些强大功能。在本系列结束时,您将 RSocket 添加到您的技能集中,以便下次您确定选项时,您将有更多协议可供选择。

让我们开始吧……

由于请求-响应对于大多数 Web 开发人员来说是熟悉的领域,因此我们将从这种模式开始我们的 RSocket 之旅。请求-响应的语义相当简单明了,您发送一个请求,您会得到一个响应。HTTP 基于这种基本的交互,而且非常常见。

在本教程中,您将了解如何使用 Spring Boot 作为服务器和终端应用程序作为客户端来使用 RSocket 进行请求-响应。

请求-响应只是 Spring 和 RSocket 支持的四种交互模型之一。我们将在以后的文章中介绍其他模型。

按照以下步骤操作时,您会注意到使用 Spring Boot 构建 RSocket 服务器所需的代码量非常少。此处已为您提供代码,但如果您愿意,也可以在几分钟内自己编写代码。

步骤 1:设置您的环境

首先,检查您是否已安装以下先决条件

  1. 版本 8 或更高版本的 Java SDK(要检查,请在终端中使用 java -version)
  2. 一个可用的 Java IDE(我使用的是 IntelliJ IDEA)
  3. 包含已克隆或解压缩的 演示代码示例 的文件夹。
  4. Linux Bash/ZSH shell(如果您是 Windows 用户,请查看下面的说明)

如果您是 Windows 用户,请切换到 Microsoft 的 Windows 子系统 Linux。Microsoft 有关如何执行此操作的说明在此处

现在,在终端中将下载的项目文件夹设为当前目录

cd spring-rsocket-demo

接下来,将 Toshiaki Maki 编写的优秀的 RSocket 客户端 CLI 下载到已克隆或解压缩代码的 rsocket-server 文件夹中。在其他地方还有一个官方的 RSocket CLI 此处,但 Toshiaki 的 CLI 更易于使用。在终端中,按如下方式下载 JAR 文件

cd rsocket-server
wget -O rsc.jar https://github.com/making/rsc/releases/download/0.4.2/rsc-0.4.2.jar

您稍后将使用此客户端与 RSocket 服务器进行通信,但现在,请通过调用 help 命令来测试它是否正常工作,如下所示

java -jar rsc.jar --help

您应该看到如下所示的输出(我已截断),解释了命令的用法和选项。

usage: rsc Uri [Options]

Non-option arguments:
[String: Uri]

Option                              Description
------                              -----------
--channel                           Shortcut of --im REQUEST_CHANNEL
-d, --data [String]                 Data. Use '-' to read data from

...

保持此终端窗口打开,您稍后将需要它。

步骤 2:检查服务器代码

在您的 IDE 中打开 rsocket-server 项目并检查代码。如您所见,在 Spring Boot 中启动 RSocket 服务器所需的代码量很少。以下是一些重点

项目文件

在项目的 pom.xml 文件中,您可以看到 Spring Boot RSocket 服务器所需的 <dependencies>。使用 Spring Boot 版本 2.2.5.RELEASE,因为在撰写本文时,此版本具有最成熟的 RSocket 功能。该项目还依赖于 lombokspring-boot-starter-rsocket 库。Lombok 为 Java 数据类添加了构造函数、getter、setter 和 equals,并且还简化了对日志等内容的访问。RSocket 的 Spring Boot Starter 将 RSocket 与 Spring Boot 集成,并在运行时自动为您配置一些 RSocket 基础结构。

应用程序属性

application.properties 文件中,RSocket 服务器的 TCP 端口设置为 7000,并且 Spring Boot 的延迟初始化功能已启用。

spring.rsocket.server.port=7000
spring.main.lazy-initialization=true

消息类

第一个需要详细查看的类称为 Message.java。此 Lombok @Data 类用于建模客户端和服务器之间(或您喜欢的“请求者”和“响应者”)的请求和响应消息。该类如下所示……

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Message {
    private String origin;
    private String interaction;
    private long index;
    private long created = Instant.now().getEpochSecond();

    public Message(String origin, String interaction) {
        this.origin = origin;
        this.interaction = interaction;
        this.index = 0;
    }

    public Message(String origin, String interaction, long index) {
        this.origin = origin;
        this.interaction = interaction;
        this.index = index;
    }
}

使用此类,您可以说明消息的来源 (origin)、它打算使用的消息传递样式 (interaction) 以及消息在一个消息序列中的序列号 (index)。Lombok 通过提供构造函数、getter、setter、toString 和 hashcode 实现来简化代码。

控制器类

RSocket 服务器控制器代码可以在RSocketController.java文件中找到。此类被注解为 Spring 的@Controller,这意味着它声明了服务端点——在本例中是 RSocket 端点。

@Controller
public class RSocketController {

    @MessageMapping("request-response")
    Message requestResponse(Message request) {
            log.info("Received request-response request: {}", request);
            // create a single Message and return it
            return new Message(SERVER, RESPONSE);
    }
}

在类中,有一个名为requestResponse()的方法,它接受单个Message对象(请求)并返回单个Message对象(响应)。

你会注意到,这个requestResponse()方法用@MessageMapping("request-response")注解修饰。此注解声明任何元数据包含 RSocket 路由request-response的消息都应由此方法处理。稍后在从客户端发送请求消息时,将使用此路由。

你注意到这与 Spring 的 REST 控制器略有不同吗?对于 REST 控制器,使用类似/hello的 URL 路径映射将 HTTP 调用与其处理程序方法关联。

代码部分就到这里。让我们试试看。

步骤 3:启动 Spring Boot RSocket 服务器

保持现有终端窗口打开,在第二个终端窗口中,将rsocket-server文件夹设置为当前目录。然后使用以下命令构建并运行 RSocket 服务器:

./mvnw clean package spring-boot:run -DskipTests=true

或者,如果您愿意,也可以使用 Java IDE 中的“构建”和“运行”命令。

步骤 4:使用 RSocket CLI 向服务器发送命令

接下来,您将使用在步骤 1 中下载和测试的 RSocket 客户端rsc.jar向正在运行的服务器发送消息。返回到您拥有--help文本的原始终端窗口,并发出以下命令:

java -jar rsc.jar --debug --request --data "{\"origin\":\"Client\",\"interaction\":\"Request\"}" --route request-response tcp://127.0.0.1:7000

你会注意到,该命令声明了一个 RSocket 消息路由(这是通过添加--route选项并指定路由名称来实现的)。在本例中,路由是request-response,它与RSocketController.java中请求响应处理程序方法中声明的@MessageMapping匹配。

命令运行时,您将在终端窗口中看到一些调试信息,解释请求响应交互期间发生的情况。它看起来像这样:

2020-02-27 11:20:21.806 DEBUG --- [actor-tcp-nio-1] i.r.FrameLogger : sending ->
Frame => Stream ID: 1 Type: REQUEST_RESPONSE Flags: 0b100000000 Length: 69
Metadata:
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 10 72 65 71 75 65 73 74 2d 72 65 73 70 6f 6e 73 |.request-respons|
|00000010| 65                                              |e               |
+--------+-------------------------------------------------+----------------+
Data:
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 7b 22 6f 72 69 67 69 6e 22 3a 22 43 6c 69 65 6e |{"origin":"Clien|
|00000010| 74 22 2c 22 69 6e 74 65 72 61 63 74 69 6f 6e 22 |t","interaction"|
|00000020| 3a 22 52 65 71 75 65 73 74 22 7d                |:"Request"}     |
+--------+-------------------------------------------------+----------------+
2020-02-27 11:20:21.927 DEBUG --- [actor-tcp-nio-1] i.r.FrameLogger : receiving ->
Frame => Stream ID: 1 Type: NEXT_COMPLETE Flags: 0b1100000 Length: 81
Data:
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 7b 22 6f 72 69 67 69 6e 22 3a 22 53 65 72 76 65 |{"origin":"Serve|
|00000010| 72 22 2c 22 69 6e 74 65 72 61 63 74 69 6f 6e 22 |r","interaction"|
|00000020| 3a 22 52 65 73 70 6f 6e 73 65 22 2c 22 69 6e 64 |:"Response","ind|
|00000030| 65 78 22 3a 30 2c 22 63 72 65 61 74 65 64 22 3a |ex":0,"created":|
|00000040| 31 35 38 32 38 30 32 34 32 31 7d                |1582802421}     |
+--------+-------------------------------------------------+----------------+
{"origin":"Server","interaction":"Response","index":0,"created":1582802421}

您看到的调试输出分为三个“消息帧”。第一个消息帧标记为Metadata。在本例中,它显示发送到服务器的路由元数据 (request-response)。第二个帧显示客户端发送到服务器的Data消息(一个 JSON 字符串)。第三个帧显示服务器返回给客户端的响应消息(也是一个 JSON 字符串)。

在最后一行,您可以看到单独打印的来自服务器的 JSON 格式的响应,确认我们的命令消息已成功接收并被服务器确认。

{"origin":"Server","interaction":"Response","index":0,"created":1582802421}

恭喜!你完成了。您刚刚使用 RSocket 发送了请求响应消息。您现在可以通过按终端窗口中的Ctrl-C或关闭它来停止 RSocket 服务器。如果您使用 IDE 运行 RSocket 服务器,则可以按照通常的方式在 IDE 中停止该进程。

工作原理

您下载的 RSocket rsc客户端使用 RSocket 消息传递协议向RSocketController发送请求消息。消息通过 TCP 发送到服务器正在等待的地址tcp://127.0.0.1:7000

路由指令在第一个消息帧中发送。此路由指令使用 CLI 客户端的--route选项设置,并设置为request-response。Spring 使用此路由信息来选择要调用的正确的@MessageMapping端点,在本例中为requestResponse(Message request)方法。然后,该方法使用它自己的消息进行响应。CLI 客户端将整个交互作为一系列消息帧打印在终端窗口中。

总结

如果您按照步骤操作,您将看到使用 Spring Boot 编写简单的 RSocket 服务器是多么容易。您检查了所需的 Java 代码,然后在本地启动了 Spring Boot 服务器。然后,您向 RSocket 服务器发送消息并观察响应。您还了解了如何使用 RSocket 消息路由功能在 Spring 中路由 RSocket 消息。在下一篇文章中,您将学习如何使用 Spring Boot 开始构建您自己的 RSocket 客户端

获取 Spring 新闻通讯

与 Spring 新闻通讯保持联系

订阅

领先一步

VMware 提供培训和认证,以加快您的进度。

了解更多

获得支持

Tanzu Spring在一个简单的订阅中提供对OpenJDK™、Spring和Apache Tomcat®的支持和二进制文件。

了解更多

即将举行的活动

查看 Spring 社区中所有即将举行的活动。

查看全部