Einführung
gRPC (gRPC Remote Procedure Call) ist ein modernes Open-Source-Remote-Prozeduraufrufs (RPC) -Framework, das von Google entwickelt wurde. Es ermöglicht die einfache Erstellung von verteilten Anwendungen und Diensten, indem es die Kommunikation zwischen ihnen vereinfacht und optimiert. gRPC basiert auf dem Protokoll Buffers (protobuf), einem effizienten binären Serialisierungsformat, das von Google ebenfalls entwickelt wurde.
Warum gRPC?
Die Hauptgründe für die Verwendung von gRPC sind:
- Leistung: Durch die Verwendung von Protokoll Buffers ist gRPC äußerst performant und ressourcenschonend.
- Sprachenunabhängigkeit: gRPC unterstützt eine Vielzahl von Programmiersprachen, darunter Java, C++, Python, Go, Ruby, und viele mehr.
- Plattformübergreifend: gRPC kann auf verschiedenen Plattformen eingesetzt werden, von mobilen Geräten bis zu Servern.
- Stream-Unterstützung: Neben einfachen RPCs unterstützt gRPC auch Client-Streaming, Server-Streaming und bidirektionales Streaming.
- Automatische Code-Generierung: Durch die Definition von Diensten in einer Protobuf-Datei kann gRPC automatisch Client- und Server-Code generieren.
Grundlagen der Protokoll Buffers (protobuf)
Bevor wir tiefer in gRPC einsteigen, ist es wichtig, die Grundlagen der Protokoll Buffers zu verstehen. Protobuf ist ein Interface Definition Language (IDL), das zur Beschreibung der Struktur von Daten und der RPC-Dienste verwendet wird.
Eine Protobuf-Datei hat die Endung .proto
und definiert Nachrichten und Dienste. Hier ist ein einfaches Beispiel:
syntax = "proto3";
package example;
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
Code-Sprache: JavaScript (javascript)
In diesem Beispiel definieren wir einen Dienst Greeter
mit einer Methode SayHello
, die eine HelloRequest
empfängt und eine HelloReply
zurückgibt.
Erstellen eines gRPC-Dienstes in Java
Voraussetzungen
Um gRPC in Java zu verwenden, benötigen Sie die folgenden Abhängigkeiten in Ihrem build.gradle
(für Gradle) oder pom.xml
(für Maven):
plugins {
id 'java'
id 'com.google.protobuf' version '0.8.16'
}
dependencies {
implementation 'io.grpc:grpc-netty-shaded:1.40.1'
implementation 'io.grpc:grpc-protobuf:1.40.1'
implementation 'io.grpc:grpc-stub:1.40.1'
compileOnly 'org.apache.tomcat:annotations-api:6.0.53'
}
protobuf {
protoc {
artifact = 'com.google.protobuf:protoc:3.17.3'
}
plugins {
grpc {
artifact = 'io.grpc:protoc-gen-grpc-java:1.40.1'
}
}
generateProtoTasks {
all().each { task ->
task.plugins {
grpc {}
}
}
}
}
Code-Sprache: JavaScript (javascript)
Protobuf-Kompilierung
Speichern Sie die oben angegebene Protobuf-Datei example.proto
im Verzeichnis src/main/proto
. Führen Sie dann den folgenden Befehl aus, um die Java-Klassen zu generieren:
./gradlew build
Implementierung des gRPC-Servers
Erstellen Sie nun die Implementierung des gRPC-Dienstes:
package example;
import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.stub.StreamObserver;
import java.io.IOException;
public class GreeterServer {
public static void main(String[] args) throws IOException, InterruptedException {
Server server = ServerBuilder.forPort(50051)
.addService(new GreeterImpl())
.build()
.start();
System.out.println("Server started, listening on " + server.getPort());
server.awaitTermination();
}
static class GreeterImpl extends GreeterGrpc.GreeterImplBase {
@Override
public void sayHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {
String greeting = "Hello, " + request.getName();
HelloReply reply = HelloReply.newBuilder().setMessage(greeting).build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
}
}
}
Code-Sprache: JavaScript (javascript)
In diesem Beispiel implementieren wir den Greeter-Dienst, der die Methode sayHello
überschreibt. Der Server wird auf Port 50051 gestartet und wartet auf Anfragen.
Implementierung des gRPC-Clients
Nun erstellen wir einen einfachen gRPC-Client, um den Dienst zu nutzen:
package example;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
public class GreeterClient {
public static void main(String[] args) throws InterruptedException {
ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 50051)
.usePlaintext()
.build();
GreeterGrpc.GreeterBlockingStub stub = GreeterGrpc.newBlockingStub(channel);
HelloRequest request = HelloRequest.newBuilder().setName("World").build();
HelloReply response = stub.sayHello(request);
System.out.println(response.getMessage());
channel.shutdown();
}
}
Code-Sprache: JavaScript (javascript)
Der Client stellt eine Verbindung zum Server her und sendet eine HelloRequest
mit dem Namen „World“. Der Server antwortet mit einer HelloReply
, die die Nachricht „Hello, World“ enthält.
Erweiterte Funktionen von gRPC
gRPC bietet neben einfachen RPCs auch erweiterte Funktionen wie Streaming und Authentifizierung.
Streaming
Es gibt vier Arten von gRPC-Methoden:
- Unary RPC: Eine einzelne Anfrage führt zu einer einzelnen Antwort (wie im obigen Beispiel).
- Server-Streaming RPC: Eine einzelne Anfrage führt zu einer Folge von Antworten.
- Client-Streaming RPC: Eine Folge von Anfragen führt zu einer einzelnen Antwort.
- Bidirektionales Streaming RPC: Eine Folge von Anfragen führt zu einer Folge von Antworten.
Hier ist ein Beispiel für einen serverseitigen Streaming-Dienst:
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
rpc StreamHello (HelloRequest) returns (stream HelloReply);
}
Implementierung des serverseitigen Streamings:
static class GreeterImpl extends GreeterGrpc.GreeterImplBase {
@Override
public void sayHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {
String greeting = "Hello, " + request.getName();
HelloReply reply = HelloReply.newBuilder().setMessage(greeting).build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
}
@Override
public void streamHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {
for (int i = 0; i < 5; i++) {
String greeting = "Hello, " + request.getName() + " - " + i;
HelloReply reply = HelloReply.newBuilder().setMessage(greeting).build();
responseObserver.onNext(reply);
try {
Thread.sleep(1000); // Simuliert eine Verzögerung
} catch (InterruptedException e) {
e.printStackTrace();
}
}
responseObserver.onCompleted();
}
}
Code-Sprache: JavaScript (javascript)
Im obigen Beispiel sendet die Methode streamHello
fünf Nachrichten mit einer Sekunde Verzögerung an den Client.
Authentifizierung
gRPC unterstützt verschiedene Authentifizierungsmethoden, einschließlich TLS und Token-basierter Authentifizierung. Hier ist ein Beispiel für die Einrichtung eines Servers mit TLS:
Server server = ServerBuilder.forPort(50051)
.useTransportSecurity(new File("server.crt"), new File("server.pem"))
.addService(new GreeterImpl())
.build()
.start();
Code-Sprache: JavaScript (javascript)
Hierbei müssen Sie die entsprechenden Zertifikatsdateien (server.crt
und server.pem
) angeben.
Fazit
gRPC ist ein leistungsstarkes und flexibles Framework für die Entwicklung verteilter Systeme. Durch seine effiziente Nutzung von Protokoll Buffers, die Unterstützung mehrerer Programmiersprachen und die vielfältigen Kommunikationsmethoden (einschließlich Streaming) bietet gRPC eine moderne Lösung für die Herausforderungen moderner vernetzter Anwendungen. Mit den hier vorgestellten Grundlagen und Beispielen können Sie beginnen, eigene gRPC-Dienste und -Clients in Java zu erstellen und die Vorteile dieser Technologie in Ihren Projekten zu nutzen.