1. Overview
1.概述
In this tutorial, we’ll take a quick look at Finagle, Twitter’s RPC library.
在本教程中,我们将快速浏览一下Finagle,Twitter的RPC库。
We’ll use it to build a simple client and server.
我们将用它来建立一个简单的客户端和服务器。
2. Building Blocks
2.积木式构件
Before we dig into the implementation, we need to get to know the basic concepts we’ll use to build our application. They are widely known but can have a slightly different meaning in Finagle’s world.
在我们深入实施之前,我们需要了解我们将用于建立我们的应用程序的基本概念。它们广为人知,但在Finagle的世界里可能有稍微不同的含义。
2.1. Services
2.1.服务
Services are functions represented by classes that take requests and return a Future containing the eventual result of the operation or information about the failure.
服务是由类代表的函数,它接受请求并返回一个Future,其中包含操作的最终结果或关于失败的信息。
2.2. Filters
2.2 过滤器
Filters are also functions. They take a request and a service, do some operations on the request, pass it to the service, do some operations on the resulting Future, and finally return the final Future. We can think of them as aspects as they can implement logic that happens around the execution of a function and alter its input and output.
过滤器也是函数。它们接收一个请求和一个服务,对请求进行一些操作,将其传递给服务,对产生的Future进行一些操作,最后返回最后的Future。我们可以将它们视为方面,因为它们可以实现发生在函数执行周围的逻辑,并改变其输入和输出。
2.3. Futures
2.3.期货
Futures represent the eventual results of the asynchronous operations. They may be in one of the three states: pending, succeeded, or failed.
期货代表异步操作的最终结果。它们可能处于三种状态之一:待定、成功或失败。
3. Service
3.服务
First, we’ll implement a simple HTTP greeting service. It’ll take the name parameter from the request and respond and add the customary “Hello” message.
首先,我们将实现一个简单的HTTP问候服务。它将从请求中获取名称参数,并响应和添加习惯的 “你好 “信息。
To do so, we need to create a class that will extend the abstract Service class from the Finagle library, implementing its apply method.
为此,我们需要创建一个类,它将扩展Finagle库中的抽象Service类,实现其apply方法。
What we’re doing looks similar to implementing a functional interface. Interestingly, though, we can’t actually use that specific feature because Finagle is written in Scala and we are taking advantage of the Java-Scala interoperability:
我们正在做的事情看起来类似于实现functional interface。但有趣的是,我们实际上不能使用这个特定的功能,因为Finagle是用Scala编写的,我们正在利用Java-Scala的互操作性。
public class GreetingService extends Service<Request, Response> {
@Override
public Future<Response> apply(Request request) {
String greeting = "Hello " + request.getParam("name");
Reader<Buf> reader = Reader.fromBuf(new Buf.ByteArray(greeting.getBytes(), 0, greeting.length()));
return Future.value(Response.apply(request.version(), Status.Ok(), reader));
}
}
4. Filter
4.过滤器
Next, we’ll write a filter that will log some data about the request to the console. Similar to Service, we will need to implement Filter‘s apply method that’ll take request and return a Future response, but this time it’ll also take the service as the second parameter.
接下来,我们将编写一个过滤器,将请求的一些数据记录到控制台。与Service类似,我们将需要实现Filter的apply方法,该方法将接收请求并返回Future响应,但这次它也将接收服务作为第二个参数。
The basic Filter class has four type-parameters but very often we don’t need to change the types of requests and responses inside the filter.
基本的过滤器类有四个类型参数,但很多时候我们不需要在过滤器内改变请求和响应的类型。
For that, we will use the SimpleFilter that merges the four type-parameters into two. We’ll print some information from the request and then simply invoke the apply method from the provided service:
为此,我们将使用SimpleFilter,将四个类型参数合并为两个。我们将从请求中打印一些信息,然后简单地从提供的服务中调用apply方法。
public class LogFilter extends SimpleFilter<Request, Response> {
@Override
public Future apply(Request request, Service<Request, Response> service) {
logger.info("Request host:" + request.host().getOrElse(() -> ""));
logger.info("Request params:");
request.getParams().forEach(entry -> logger.info("\t" + entry.getKey() + " : " + entry.getValue()));
return service.apply(request);
}
}
5. Server
5.服务器
Now we can use the service and the filter to build a server that will actually listen for requests and process them.
现在我们可以使用服务和过滤器来建立一个服务器,该服务器将实际监听请求并处理它们。
We’ll provision this server with a service that contains both our filter and service chained together with the andThen method:
我们将为这个服务器提供一个服务,这个服务包含我们的过滤器和服务,用andThen方法链在一起。
Service serverService = new LogFilter().andThen(new GreetingService());
Http.serve(":8080", serverService);
6. Client
6.客户
Finally, we need a client to send a request to our server.
最后,我们需要一个客户端向我们的服务器发送一个请求。
For that, we’ll create an HTTP service using the convenient newService method from Finagle’s Http class. It’ll be directly responsible for sending the request.
为此,我们将使用Finagle的newService方法创建一个HTTP服务,a href=”https://twitter.github.io/finagle/docs/com/twitter/finagle/Http$.html”>Http类。它将直接负责发送请求。
Additionally, we’ll use the same logging filter we implemented before and chain it with the HTTP service. Then, we’ll just need to invoke the apply method.
此外,我们将使用我们之前实现的相同的日志过滤器,并将其与HTTP服务链接。然后,我们只需要调用apply方法。
That last operation is asynchronous and its eventual results are stored in the Future instance. We could wait for this Future to succeed or fail but that would be a blocking operation and we may want to avoid it. Instead, we can implement a callback to be triggered when the Future succeeds:
最后一个操作是异步的,其最终结果存储在Future实例中。我们可以等待这个Future成功或失败,但这将是一个阻塞操作,我们可能希望避免它。相反,我们可以实现一个回调,当Future成功时被触发。
Service<Request, Response> clientService = new LogFilter().andThen(Http.newService(":8080"));
Request request = Request.apply(Method.Get(), "/?name=John");
request.host("localhost");
Future<Response> response = clientService.apply(request);
Await.result(response
.onSuccess(r -> {
assertEquals("Hello John", r.getContentString());
return BoxedUnit.UNIT;
})
.onFailure(r -> {
throw new RuntimeException(r);
})
);
Note that we return BoxedUnit.UNIT. Returning Unit is the Scala’s way of coping with void methods, so we do it here to maintain interoperability.
请注意,我们返回BoxedUnit.UNIT. 返回Unit是Scala应对void方法的方式,所以我们在这里这样做是为了维护互操作性。
7. Summary
7.摘要
In this tutorial, we learned how to build a simple HTTP server and a client using Finagle as well as how to establish communication between them and exchange messages.
在本教程中,我们学习了如何使用Finagle建立一个简单的HTTP服务器和一个客户端,以及如何在它们之间建立通信并交换信息。
As always, the source code with all the examples can be found over on GitHub.
一如既往,包含所有示例的源代码可以在GitHub上找到。