领先一步
VMware 提供培训和认证,以加速您的进步。
了解更多欢迎来到 You May Not Need Another Library For That (YMNNALFT) 的另一期!自 2016 年以来,我花了很多时间在我的 Spring Tips 视频 中阐明(或者至少尝试阐明!)Spring 生态系统中一些更大的机会。然而,今天我以不同的精神来到这里,希望专注于那些发挥出色作用、有时隐藏的小巧宝石,它们可能会让你免于使用额外的第三方依赖项及其隐含的复杂性。
集成两个由公共网络(可能不稳定且负载过重)分隔的服务是最具挑战性的计算机科学问题之一。
题外话:当然,计算机科学中最具挑战性的问题是 CSS 中的垂直布局。
你可以写一整本书来介绍集成不同系统和服务的方法。但是,Gregor Hohpe 和 Bobby Woolf 已经在他们的 企业集成模式 书中做了这件事,所以我将使用他们的其中一个列表。
消息传递是指生产者将消息(包含信封和有效负载)发送到可靠的中间代理。该代理充当生产者和消费者之间消息的传递服务。
RPC,或远程过程调用……不是那个。有风险的过程调用?不……相对轻松的灾难?不……远程过程调用!就是这样。RPC 是指消费者通过某种网络协议(如 SOAP-RPC、Hessian、Burlap、Spring 自己的 HTTP Invoker、XML RPC、EJB、RMI、DCOM、CORBA 等)在远程对象上调用方法。这种体验旨在让你感觉像在同一虚拟机中的本地对象上调用方法一样。
文件传输是指生产者将文件传输到共享的、商定的(网络)文件系统,而消费者则使用存放在那里的消息。这是如今许多批处理流程的基础。如果你还没有,你应该看看 Spring Batch。十个牙医中有九个同意:Spring Batch 保持牙齿清洁,并使集成流程精简。
共享数据库是指生产者和消费者从同一张表中读取数据(不建议)。事实上,在目前,特别是微服务环境中,这有点像反模式。
关于 RPC 与消息传递作为可靠集成生产者和消费者方式的优缺点,肯定需要讨论,但这里不是讨论这些,因为我认为我找到了最佳折衷方案:响应式、有效负载无关、闪电般快速、可观察的 RSocket。RSocket 是一个二进制协议,最初由 Netflix 的工程师开发,他们离开后继续在 Facebook 工作。该协议专为规模和速度而构建,并规避了 HTTP 1-2 和 gRPC 的许多限制。它是一个令人兴奋的协议,有很多原因
.io
域名,众所周知,这对注定要进入云端的技术的成功至关重要它是一个以消息信封为中心的协议,但使用起来非常简单,如果你想体验 RPC 的生活,它甚至更简单。
各种语言都提供了大量客户端,包括 Java。Java 客户端构建在 Project Reactor 之上。即使 Spring 本身没有提供原生支持,将 RSocket 集成到 Spring 应用程序中也非常简单——非常简单!我说。但 Spring 本身确实提供了原生支持,而且非常棒。该集成使用与 Spring Framework 4 中原始 WebSocket 支持相同的组件模型。
让我们看一个简单的示例服务。
你需要以下依赖项。
org.springframework.boot
: spring-boot-starter-rsocket
这是代码
package bootiful.rpc.server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.messaging.handler.annotation.DestinationVariable;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Controller;
import java.util.Locale;
@SpringBootApplication
public class BootifulApplication {
public static void main(String[] args) {
System.setProperty("spring.profiles.active", "rpcserver");
SpringApplication.run(BootifulApplication.class, args);
}
}
@Controller
class GreetingsController {
@MessageMapping("greetings.{lang}")
String greet(@DestinationVariable("lang") Locale lang, @Payload String name) {
System.out.println("locale: " + lang.getLanguage());
return "Hello, " + name + "!";
}
}
这是我放在 application.properties
中的内容
spring.rsocket.server.port=8888
spring.main.web-application-type=none
控制器是一个带有方法的对象,就像 RPC 一样,但客户端严格来说不必等待响应。它可以将线程置于后台或完全断开连接。双赢。该协议在幕后比组件模型更以信封和有效负载为中心,因此我们获得了两全其美。
我们的服务已启动并运行。如果你想调用它,你可以使用 方便的 rsc
CLI。
rsc tcp://127.0.0.1:8888 -r greetings.en -d 'Josh'
你应该会得到如下输出
Hello, Josh!
这可能就足够了,但我们中的大多数人希望从我们的客户端代码中与我们的 RSocket 服务通信。有来自多种不同编程语言的客户端,包括但不限于 JavaScript、Go、.NET(C#)、Rust、C++、Ruby、Python 等。(而且,最糟糕的情况是,你总是可以包装 C++ 或 Java 端口,对吧?)
让我们看看如何构建一个客户端来与新创建的服务通信。我们将使用 RSocketRequester
,这是一个我们可以用来与 RSocket 端点通信的客户端。
你需要以下依赖项
org.springframework.boot
: spring-boot-starter-rsocket
这是代码
package bootiful.rpc.client;
import lombok.SneakyThrows;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.messaging.rsocket.RSocketRequester;
import java.util.Locale;
@SpringBootApplication
public class BootifulApplication {
@SneakyThrows
public static void main(String[] args) {
System.setProperty("spring.profiles.active", "rpcclient");
SpringApplication.run(BootifulApplication.class, args);
Thread.sleep(5_000);
}
@Bean
RSocketRequester rSocketRequester(RSocketRequester.Builder builder) {
return builder.tcp("localhost", 8888);
}
@Bean
ApplicationListener<ApplicationReadyEvent> ready(RSocketRequester rSocketRequester) {
return event -> rSocketRequester //
.route("greetings.{lang}", Locale.ENGLISH) //
.data("World").retrieveMono(String.class)//
.subscribe(greetings -> System.out.println("got: " + greetings));
}
}
这是我放在 application.properties
中的内容
spring.main.web-application-type=none
在这里,你可以看到 RSocket 服务的默认客户端体验更像是 HTTP 端点或与消息队列的交换。我们正在向端点发送请求消息,这些端点更像是 URI,而不是分布式方法。也就是说,如果你真的非常喜欢 RPC,并且不介意一个可选的额外依赖项。你可以考虑实验性的 Spring Retrosocket 项目,我们推出该项目正是为了支持这种情况。它提供了类似 Netflix feign 的 RPC 体验,但适用于 RSocket。
你喜欢这种快速了解宝石的方法吗?你学到什么了吗?与往常一样,我很乐意听到你的意见,所以请在 Twitter 上发表你的看法(@starbuxman)!我将继续发布 YMNNALFT 的下一期,所以请务必不要错过。