Einführung in Finagle

1. Übersicht

In diesem Tutorial werfen wir einen kurzen Blick auf Finagle, die RPC-Bibliothek von Twitter.

Wir werden es verwenden, um einen einfachen Client und Server zu erstellen.

2. Bausteine

Bevor wir uns mit der Implementierung befassen, müssen wir uns mit den grundlegenden Konzepten vertraut machen, die wir zum Erstellen unserer Anwendung verwenden. Sie sind weithin bekannt, können aber in Finagles Welt eine etwas andere Bedeutung haben.

2.1. Dienstleistungen

Services sind Funktionen, die durch Klassen dargestellt werden, die Anforderungen entgegennehmen und eine Zukunft zurückgeben, die das endgültige Ergebnis der Operation oder Informationen zum Fehler enthält.

2.2. Filter

Filter sind auch Funktionen. Sie nehmen eine Anforderung und einen Dienst entgegen, führen einige Vorgänge für die Anforderung aus, übergeben sie an den Dienst, führen einige Vorgänge für die resultierende Zukunft aus und geben schließlich die endgültige Zukunft zurück . Wir können sie als Aspekte betrachten, da sie Logik implementieren können, die um die Ausführung einer Funktion herum geschieht, und deren Eingabe und Ausgabe ändern können.

2.3. Futures

Futures repräsentieren die möglichen Ergebnisse der asynchronen Operationen. Sie können sich in einem der drei Zustände befinden: ausstehend, erfolgreich oder fehlgeschlagen.

3. Service

Zunächst implementieren wir einen einfachen HTTP-Begrüßungsdienst. Es nimmt den Parameter name aus der Anfrage und antwortet und fügt die übliche "Hallo" -Nachricht hinzu.

Um dies zu tun, müssen wir eine Klasse erstellen, die die abstrakte werden erweitern Service - Klasse von der Finagle Bibliothek, die Umsetzung ihrer Anwendung Methode.

Was wir tun, ähnelt der Implementierung einer funktionalen Schnittstelle. Interessanterweise können wir diese spezielle Funktion jedoch nicht verwenden, da Finagle in Scala geschrieben ist und wir die Interoperabilität zwischen Java und Scala nutzen:

public class GreetingService extends Service { @Override public Future apply(Request request) { String greeting = "Hello " + request.getParam("name"); Reader reader = Reader.fromBuf(new Buf.ByteArray(greeting.getBytes(), 0, greeting.length())); return Future.value(Response.apply(request.version(), Status.Ok(), reader)); } }

4. Filtern

Als Nächstes schreiben wir einen Filter, der einige Daten über die Anforderung an die Konsole protokolliert. Ähnlich Dienst , müssen wir implementieren Filter ‚s anwenden Methode , die Anfrage übernehmen würde und eine Rückkehr Zukunft Antwort, diesmal aber es wird auch den Dienst als zweiten Parameter übernehmen.

Die grundlegende Filterklasse hat vier Typparameter, aber sehr oft müssen wir die Arten von Anforderungen und Antworten innerhalb des Filters nicht ändern.

Dazu verwenden wir den SimpleFilter , der die vier Typparameter in zwei zusammenführt. Wir drucken einige Informationen aus der Anfrage und rufen dann einfach die Apply- Methode des bereitgestellten Dienstes auf:

public class LogFilter extends SimpleFilter { @Override public Future apply(Request request, Service 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

Jetzt können wir den Dienst und den Filter verwenden, um einen Server zu erstellen, der tatsächlich auf Anforderungen wartet und diese verarbeitet.

Wir stellen diesem Server einen Dienst zur Verfügung, der sowohl unseren Filter als auch unseren Dienst enthält, die mit der andThen- Methode verkettet sind :

Service serverService = new LogFilter().andThen(new GreetingService()); Http.serve(":8080", serverService);

6. Kunde

Schließlich benötigen wir einen Client, um eine Anfrage an unseren Server zu senden.

Dafür werden wir einen HTTP - Dienst mit der bequem erstellen newService Methode von Finagles Http Klasse. Es ist direkt für das Senden der Anfrage verantwortlich.

Darüber hinaus verwenden wir denselben Protokollierungsfilter, den wir zuvor implementiert haben, und verketten ihn mit dem HTTP-Dienst. Dann werden wir brauchen nur die aufrufen anwenden Methode.

Diese letzte Operation ist asynchron und ihre eventuellen Ergebnisse werden in der Future- Instanz gespeichert . Wir könnten warten, bis diese Zukunft erfolgreich ist oder fehlschlägt, aber das wäre eine blockierende Operation, und wir möchten sie möglicherweise vermeiden. Stattdessen können wir einen Rückruf implementieren, der ausgelöst wird, wenn die Zukunft erfolgreich ist:

Service clientService = new LogFilter().andThen(Http.newService(":8080")); Request request = Request.apply(Method.Get(), "/?name=John"); request.host("localhost"); Future response = clientService.apply(request); Await.result(response .onSuccess(r -> { assertEquals("Hello John", r.getContentString()); return BoxedUnit.UNIT; }) .onFailure(r -> { throw new RuntimeException(r); }) );

Beachten Sie, dass wir BoxedUnit.UNIT zurückgeben. Returning Unit ist die Methode der Scala, mit ungültigen Methoden umzugehen. Deshalb tun wir dies hier, um die Interoperabilität aufrechtzuerhalten.

7. Zusammenfassung

In diesem Tutorial haben wir gelernt, wie man mit Finagle einen einfachen HTTP-Server und einen Client erstellt und wie man die Kommunikation zwischen ihnen herstellt und Nachrichten austauscht.

Wie immer finden Sie den Quellcode mit allen Beispielen auf GitHub.