[JAVA] Probieren Sie gRPC im Spring Boot & Spring Cloud-Projekt (Mac OS) aus.

[Aktualisiert am 05. Mai 2019 um 18:00 Uhr] In letzter Zeit scheint gRPC für die Kommunikation zwischen Knoten auf verteilten Systemen beliebter zu sein als REST, daher habe ich es versucht. Darüber hinaus wird gRPC als Bibliothek in Java bereitgestellt, und im Frühjahr wird ein Starter zum Booten von LogNet bereitgestellt. Es scheint, dass es gibt, also verwenden Sie es auf Spring Boot. Außerdem gehe ich davon aus, dass es auf einem verteilten System verwendet wird, wenn es in Zukunft in die Praxis umgesetzt werden soll. Deshalb habe ich beschlossen, es in das Spring Cloud-Projekt aufzunehmen und auszuführen.

Überraschenderweise gab es einige süchtig machende Punkte, bevor ich sie gerade verschoben habe. Dieses Mal werde ich diese Punkte teilen und beschreiben, was ich bis zu dem Punkt bestätigt habe, an dem das Projekt normal funktioniert.

Umgebung

Projektstruktur

Ich kann erwähnen, was in Spring Cloud separat implementiert ist, aber ich habe im folgenden Projekt die gRPC-Kommunikation für den Lastausgleich durch Eureka und Ribbon versucht.

プロジェクト構成

Wenn der Benutzer eine HTTP-Anfrage an die oben genannte "Eureka-lb-Demo" sendet, API an "Eureka-lb-Demo" → "Eureka-Client-Demo" durch gRPC-Kommunikation. In Form eines Anrufs. Da der Projektname gemäß der Struktur von Eureka angegeben wird, ist das Gegenteil der Fall, jedoch als gRPC

Ist die Beziehung.

eureka-demo, config-server-demoHat nichts mit diesem Thema zu tun. Der Teil, der sich auf das Thema bezieht, ist nur der weiße Teil.

プロジェクト構成2

Serviceinhalt

Es ist nicht die Essenz dieser Zeit, aber ich werde es kurz erklären, damit Sie nicht den Überblick verlieren, was Sie tun, wenn Sie sich das Code-Snippet ansehen. Dieses Mal haben wir einen Dienst implementiert, mit dem Sie Geräteinformationen abrufen können, indem Sie den Schulnamen als Parameter übergeben. Wenn die Anfrage von "eureka-lb-demo" empfangen wird, fragt sie intern die API von "eureka-client-demo" ab, die "getEquipmentInfo" genannt wird. Daher heißt die Schnittstellendefinition dieses Mal "EquipmentService".

Annahme

Bevor ich zur Implementierung übergehe, werde ich kurz die Annahmen von gRPC erläutern. gRPC definiert eine Datei mit dem Namen `.proto``` und kompiliert sie mit einem Compiler namens protoc. Die Quelle des API-Teils wird automatisch generiert. Gleiches Gefühl wie SOAP. Erstellen Sie nach dem Erstellen dieser Datei einen Klassenpfad von `src / main / proto``` und erstellen Sie ihn.

Wenn Sie in maven ein Plugin definieren, können Sie dem Build-Pfad ohne Erlaubnis eine automatisch generierte Quelle hinzufügen, indem Sie wie gewohnt erstellen.

Der Grund für den Namen ** proto ** ist, dass er eine Technologie namens Protokollpuffer verwendet, aber die Erklärung wird weggelassen, weil sie gegen den Zweck dieser Zeit verstößt.

Implementierung

Gemeinsam für Server und Client

Die Protodatei wurde so erstellt. Ich möchte das Objekt als Listentyp zurückgeben, wenn der Name der Parameterschule in der Datenbank vorhanden ist. Wenn es nicht existiert, wird nur die Nachricht zurückgegeben. Daher definiert EquipmentResponse die Nachricht als erstes Feld und die Liste der Java-Objekte als zweites Feld.

syntax = "proto3";

option java_multiple_files = true;
option java_package = "com.example.ek.eureka_client_demo.equipment";

package equipment_proto;

service EquipmentService {
	rpc getEquipment (EquipmentRequest) returns (EquipmentResponse);
}

message EquipmentRequest{
	string schoolName = 1;
}

message EquipmentResponse{
	string message = 1;
	repeated EquipmentInfo equipmentInfo = 2;
}

message EquipmentInfo{
	string catagory = 1;
	string name = 2;
}

Die im EquipmentService definierte getEquipment ist die API zum Abrufen von Geräteinformationen.

Unten finden Sie die detaillierte Grammatik von Proto. Protocol Buffers Language Guide (proto3)

Serverseite (`` `eureka-client-demo```)

<!-- gRPC server -->
<dependency>
  <groupId>io.github.lognet</groupId>
  <artifactId>grpc-spring-boot-starter</artifactId>
</dependency>

Da der oben beschriebene Prototyp verwendet werden muss, fügen Sie als Nächstes Folgendes unter dem Tag `<build>` hinzu. Bitte beachten Sie auch den Referenzartikel [^ 1] für diesen Bereich.


<extensions>
  <extension>
    <groupId>kr.motd.maven</groupId>
    <artifactId>os-maven-plugin</artifactId>
    <version>1.5.0.Final</version>
  </extension>
</extensions>

//Abkürzung

<plugin>
  <groupId>org.xolstice.maven.plugins</groupId>
  <artifactId>protobuf-maven-plugin</artifactId>
  <version>0.5.1</version>
  <configuration>
    <protocArtifact>com.google.protobuf:protoc:3.5.1-1:exe:${os.detected.classifier}</protocArtifact>
    <pluginId>grpc-java</pluginId>
    <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.18.0:exe:${os.detected.classifier}</pluginArtifact>
  </configuration>
  <executions>
    <execution>
      <goals>
        <goal>compile</goal>
        <goal>compile-custom</goal>
      </goals>
    </execution>
  </executions>
</plugin>

Zunächst ist hier ein Fehler aufgetreten. Unter meinem MacOS wurde die Fehlermeldung angezeigt, dass `$ {os.detected.classifier}` nicht identifiziert werden konnte. Daher habe ich die Eigenschaft angegeben und übertroffen. Es scheint, dass Profileinstellungen mit `` `settings.xml``` verwendet werden können, aber ich gebe Eigenschaften für dieselbe POM-Datei an. Bitte beachten Sie, dass es in Windows möglich war, in den Status von Variablen zu wechseln. Es scheint also, dass dies je nach Betriebssystem möglich oder nicht möglich ist.

<properties>
  <java.version>1.8</java.version>
  <spring-cloud.version>Greenwich.RC2</spring-cloud.version>
  <os.detected.classifier>osx-x86_64</os.detected.classifier>
</properties>

Wenn Sie in diesem Status erstellen, wird der Quellcode für gRPC automatisch generiert. Implementieren Sie einen Controller, der Anforderungen von `` `eureka-lb-demo``` (clientseitig) unter Verwendung des automatisch generierten Codes akzeptiert. Der erstellte Controller lautet wie folgt.


package com.example.ek.eureka_client_demo.equipment;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.collections.CollectionUtils;
import org.lognet.springboot.grpc.GRpcService;
import org.springframework.stereotype.Controller;

import com.example.ek.eureka_client_demo.equipment.EquipmentServiceGrpc.EquipmentServiceImplBase;

import io.grpc.stub.StreamObserver;

@GRpcService // (1)
@Controller
public class EquipmentController extends EquipmentServiceImplBase { // (2)

	private static Map<String, List<Equipment>> schoolEquipmentDB; // (3)

	@Override
	public void getEquipment(EquipmentRequest req, StreamObserver<EquipmentResponse> resObserber) { // (4)
		String schoolNm = req.getSchoolName(); // (5)
		List<Equipment> list = schoolEquipmentDB.get(schoolNm);

		EquipmentResponse equipmentResponsse = null;
		if (CollectionUtils.isEmpty(list)) {
			equipmentResponsse = EquipmentResponse.newBuilder()
					.setMessage(
							"There is no equipment in this scool " + schoolNm + System.getProperty("line.separator"))
					.build(); // (6)
			resObserber.onNext(equipmentResponsse); // (8)
		}
		//Wann können Geräteinformationen abgerufen werden
		else {
			EquipmentResponse.Builder responseBuilder = EquipmentResponse.newBuilder();
			for (Equipment eq : list) {
				EquipmentInfo eqInfo = EquipmentInfo.newBuilder()
						.setCatagory(eq.getCategory())
						.setName(eq.getName())
						.build(); // (7)
				responseBuilder.addEquipmentInfo(eqInfo);
			}
			EquipmentResponse res = responseBuilder.setMessage("").build();
			resObserber.onNext(res); //(8)
		}
		resObserber.onCompleted(); // (9)
	}

	// (3)
	static {
		schoolEquipmentDB = new HashMap<String, List<Equipment>>();

		List<Equipment> lst = new ArrayList<Equipment>();
		Equipment eqp = new Equipment("chair", "High Grade Chair I");
		lst.add(eqp);
		eqp = new Equipment("desk", "High Grade Desk I");
		lst.add(eqp);

		schoolEquipmentDB.put("abcschool", lst);

		lst = new ArrayList<Equipment>();
		eqp = new Equipment("chair", "Low Grade Chair I");
		lst.add(eqp);
				eqp = new Equipment("desk", "Low Grade Desk I");
				lst.add(eqp);

		schoolEquipmentDB.put("xyzschool", lst);

		//Überprüfen Sie in der DB
		System.out.println("School Equipment information are as below.");
		for (Entry<String, List<Equipment>> entry : schoolEquipmentDB.entrySet()) {
			System.out.println("School: " + entry.getKey());
			for (Equipment e : entry.getValue()) {
				System.out.println("    Equipment:" + e.getCategory() + "," + e.getName());
			}
		}

	}
No. Erläuterung
(1) Fügen Sie diese Anmerkung hinzu, wenn Sie gRPC verwenden.
(2) Automatisch erzeugtEquipmentServiceImplBaseErben. Es gibt einige automatisch generierte Dateien,.Von ptoro angegebener Dienstname+ ImplBaseIst.
(3) Da das Erstellen einer Datenbank mühsam war, wurde ein DB-Mock erstellt, der nur einen Wert in eine mit static erstellte Variable einfügt.
(4) ich auch.Von proto angegebener MethodennameÜberschreiben.
(5) .protoWie in der Anfrage definiertschoolNameDa ich den Parameter definiert habe, holen Sie ihn aus dem Anforderungsobjekt und den Wert aus dem DB-Mock. Darunter befindet sich die Quelle für die Rückgabe einer Antwort.
(6) Die Antwort legt auch den Wert der automatisch generierten Bean mit dem Builder-Muster fest. Hier wird nur eine Meldung gesetzt, wenn die Geräteinformationen nicht abgerufen werden können.
(7) Dies ist ein Zweig, wenn ein Wert genommen wird, keine Nachricht, sondern ein Objekt von ListenelementenEquipmentInfo(Dies ist auch eine automatisch generierte Quelle)Stellen Sie den Wert auf ein. Wie das Antwortobjekt wird auch hier ein Objekt mit dem Builder-Muster erstellt.
(8) Es ist ein Argument der MethodeStreamObservervononNextSenden Sie einen Wert an die Clientseite, indem Sie im Methodenargument ein Antwortobjekt festlegen.
(9) Zum Schluss die Kommunikation beendenonCompleteRufen Sie die Methode auf.

Auch Eigenschafteneinstellungen für gRPC

application.yml


## grpc settings
grpc:
 port: 6565

Versuchen Sie dann, mit `` `$ mvn clean install spring-boot: run``` zu erstellen und zu booten. Ich habe den folgenden Fehler erhalten.

***************************
APPLICATION FAILED TO START
***************************

Description:

An attempt was made to call the method com.google.common.base.Preconditions.checkArgument(ZLjava/lang/String;CLjava/lang/Object;)
V but it does not exist. Its class, com.google.common.base.Preconditions, is available from the following locations:

    jar:file:/Users/***/.m2/repository/com/google/guava/guava/16.0/guava-16.0.jar!/com/google/common/base/Preconditions.class

Als ich es nachgeschlagen habe, gab es ein Git-Problem, dass die Guavenbibliothek alt war und aktualisiert werden sollte. Als ich also nach der Quelle der Guave mit `` `$ mvn dependency: tree``` gesucht habe

[INFO] |  +- com.netflix.eureka:eureka-client:jar:1.9.8:compile
[INFO] |  |  +- org.codehaus.jettison:jettison:jar:1.3.7:runtime
[INFO] |  |  |  \- stax:stax-api:jar:1.0.1:runtime
[INFO] |  |  +- com.netflix.netflix-commons:netflix-eventbus:jar:0.3.0:runtime
[INFO] |  |  |  +- com.netflix.netflix-commons:netflix-infix:jar:0.3.0:runtime
[INFO] |  |  |  |  +- commons-jxpath:commons-jxpath:jar:1.3:runtime
[INFO] |  |  |  |  +- joda-time:joda-time:jar:2.10.1:runtime
[INFO] |  |  |  |  \- org.antlr:antlr-runtime:jar:3.4:runtime
[INFO] |  |  |  |     +- org.antlr:stringtemplate:jar:3.2.1:runtime
[INFO] |  |  |  |     \- antlr:antlr:jar:2.7.7:runtime
[INFO] |  |  |  \- org.apache.commons:commons-math:jar:2.2:runtime
[INFO] |  |  +- com.netflix.archaius:archaius-core:jar:0.7.6:compile
[INFO] |  |  |  \- com.google.guava:guava:jar:16.0:compile

Es scheint, dass das Glas von eureka-client und der Boot-Starter von grpc nicht übereinstimmen. Das JAR für Eureka-Client wird wie folgt ausgeschlossen und neu erstellt und ausgeführt.

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  <exclusions>
          <exclusion>
              <groupId>com.google.guava</groupId>
              <artifactId>guava</artifactId>
          </exclusion>
    </exclusions>
</dependency>

Spring Cloud-Projekte enthalten grundsätzlich ein Guavenglas. Wenn Sie also gRPC verwenden möchten, müssen Sie die Version richtig anpassen. Ich habe auch Konfigurationsserver und Hystrix zur Abhängigkeit hinzugefügt, und verschiedene Versionen von Guave waren in jeder enthalten, daher habe ich dort auch Ausschlusseinstellungen hinzugefügt.

Das Build-Ergebnis war erfolgreich.

Started EurekaClientDemoApplication in 15.476 seconds (JVM running for 56.095)

o.l.springboot.grpc.GRpcServerRunner     : gRPC Server started, listening on port 6565.

Client-Seite (`` `eureka-lb-demo```)

Wie auf der Serverseite schließt pom Guave aus und fügt nur den Boot-Starter von gRPC hinzu, sodass ich ihn weglassen werde. Außerdem ist die `` `.proto```-Datei genau die gleiche wie die auf der Serverseite, und der Build → -Quellcode wird automatisch generiert, was nicht nur für die Client-Seite gilt. Da der auf der Clientseite eindeutige Inhalt nur die aufrufende Methode (Java-Code) ist, wird nur der Controller beschrieben.

@RestController
public class SchoolController {

	@Autowired
	EurekaClient client; // (1)

  //Kürzung

	@GetMapping(value = "/getEquipmentInfo/{schoolname}")
	public String getEquipments(@PathVariable String schoolname) {
		System.out.println("Getting School details for " + schoolname);

		InstanceInfo instance = client.getNextServerFromEureka("studentService", false);
		ManagedChannel channel = ManagedChannelBuilder.forAddress(instance.getIPAddr(), 6565)
				.usePlaintext().build(); // (2)

		EquipmentServiceBlockingStub stb = EquipmentServiceGrpc.newBlockingStub(channel);
		EquipmentRequest req = EquipmentRequest.newBuilder().setSchoolName(schoolname).build();
		EquipmentResponse res = stb.getEquipment(req); // (3)

		if (StringUtils.hasLength(res.getMessage())) {
			return res.getMessage();
		}

		StringBuilder sb = new StringBuilder();
		for (EquipmentInfo eq : res.getEquipmentInfoList()) {
			sb.append(editResponseForEquipment(eq));
			sb.append(System.getProperty("line.separator"));
		}

		return sb.toString();
	}


	private String editResponseForEquipment(EquipmentInfo eq) {
		return "Category: " + eq.getCatagory() + ", " + "EquipmentName: " + eq.getName() + ";";
	}
No. Erläuterung
(1) eureka-client-demoUm Informationen nebenbei zu bekommenEurekaClientDI.
(2) So verwenden Sie gRPCMannagedChannelBenutzen. Zur KanalerzeugungManagedChannelBuilder.forAddressZueureka-client-demoÜbergeben Sie die IP und den Port von. Ich eureka-client-Ich habe den Port fest codiert, weil ich einen REST-Port für die Kommunikation mit der Demo habe, aber wenn ich nur gRPC verwendeinstance.getPortEs ist okay.
(3) Dies ist eine automatisch generierte Stub-Klasse, wie diese Bibliothek geschrieben wirdEquipmentServiceBlockingStubKommunizieren Sie mit. Nach dem Einstellen der Parameter in der Anfrage der Reststb.getEquipmentIm Argument der Methode wird eine Anfrage gesetzt und eine Antwort empfangen.

Lauf

Wenn Sie dagegen eine HTTP-Anfrage senden, können Sie das Ergebnis wie folgt sicher abrufen.

$ curl http://localhost:8086/getEquipmentInfo/abcschool
Category: chair, EquipmentName: High Grade Chair I;
Category: desk, EquipmentName: High Grade Desk I;

Wenn ein Schulname angegeben wird, der in der Datenbank nicht vorhanden ist

$ curl http://localhost:8086/getEquipmentInfo/defschool
There is no equipment in this school defschool

Daher ist ersichtlich, dass sowohl der Listentyp von Objekten als auch die Nachricht von String wie beabsichtigt kommunizieren können.

Quellcode

Die Quelle ist wie folgt, obwohl verschiedene andere Inhalte gemischt sind. Quellcode

Alle Eigenschaftseinstellungswerte, die nicht mit gRPC zusammenhängen, werden in `` config-server-demo``` zusammengefasst, und jedes Projekt hat `src / main / resource / bootstrap.yml``` in config-server. Beim Surfen, weil es zum Einstellungswert für das Projekt gehen soll (config) Bitte seien Sie vorsichtig.

Referenz

Recommended Posts

Probieren Sie gRPC im Spring Boot & Spring Cloud-Projekt (Mac OS) aus.
Versuchen Sie Spring Boot auf dem Mac
Starten Sie mit IntelliJ ein (altes) Spring Boot-Projekt
Erstellen Sie mit IntelliJ ein Java Spring Boot-Projekt
Führen Sie ein Spring Boot-Projekt mit VS-Code aus
Java-Tipps - Erstellen Sie mit Gradle ein Spring Boot-Projekt
Zeigen Sie die Gradle-Aufgabe im Spring Boot-Projekt an
Microservices in Spring Cloud
Legen Sie den Kontextparameter in Spring Boot fest
Versuchen Sie Spring Boot von 0 bis 100.
Spring Boot 2 Multiprojekt mit Gradle
Wichtige Änderungen in Spring Boot 1.5
NoHttpResponseException in Spring Boot + WireMock
Versuchen Sie es mit Spring Boot Security
Frühlingsstiefel Hallo Welt in Eclipse
Spring Boot-Anwendungsentwicklung in Eclipse
gRPC auf Spring Boot mit grpc-spring-boot-Starter
Spring Boot 2.2 unterstützt jetzt RSocket. Probieren Sie es aus
Versuchen Sie, C-Sprache und Swift in einem Projekt (OS X, Linux) zu mischen.
Schreiben Sie den Testcode mit Spring Boot
Spring Boot: Restful API-Beispielprojekt
Was ist @Autowired im Spring Boot?
Google Cloud Platform mit Spring Boot 2.0.0
Implementieren Sie die Spring Boot-Anwendung in Gradle
Versuchen Sie, Spring Boot auf Kubernetes auszuführen
Verwendung von Thymeleaf mit Spring Boot
Versuchen Sie, mehr C-Sprache und Swift in einem Projekt (OS X, Linux) zu mischen.
Erstellen Sie mit Intellij ein Spring Boot-Projekt und beenden Sie es sofort nach dem Start
Eine Geschichte über ein in Java geschriebenes Spring Boot-Projekt, das Kotlin unterstützt
Versuchen Sie, Project Euler in Java zu lösen
Spring Boot Umgebungskonstruktionsnotiz auf Mac
Erstellen Sie mit Gradle ein Spring Boot + Docker-Image
Statische Dateizugriffspriorität beim Spring Boot
Spring Boot-Protokoll im JSON-Format ausgeben
Memorandum zum Herunterladen lokaler Dateien mit Spring Boot
Versuchen Sie es mit Spring Boot mit VS-Code
Verwenden Sie die DynamoDB-Abfragemethode mit Spring Boot
Versuchen Sie Spring Boot 1 (Umgebungskonstruktion ~ Tomcat-Start)
DI SessionScope Bean im Spring Boot 2-Filter
Ändern Sie das Sitzungszeitlimit in Spring Boot
SameSite-Cookie im Spring Boot (Spring Web MVC + Tomcat)
Testen Sie den Controller mit Mock MVC im Spring Boot
Asynchrone Verarbeitung mit regelmäßiger Ausführung in Spring Boot
Anforderungs- und Antwortprotokolle mit Spring Boot ausgeben
Fügen Sie mehrere Hauptklassen in ein Frühlingsprojekt ein
Versuchen Sie die LDAP-Authentifizierung mit Spring Security (Spring Boot) + OpenLDAP
Versuchen Sie, die Cloud Vision-API von GCP in Java zu verwenden
Versuchen Sie, die Anmeldefunktion mit Spring Boot zu implementieren
Servlet-Filter mit Spring Boot verwenden [Spring Boot 1.x, 2.x kompatibel]
So fügen Sie in Spring Boot einen Klassenpfad hinzu
Erstellen Sie mit Gradle Spring Boot-Projekte nach Umgebung
So binden Sie mit einer Eigenschaftendatei in Spring Boot
Versuchen Sie, die Migration mit Spring Boot Flyway zu automatisieren
Anmerkungen, die in Spring Boot-Aufgabenverwaltungstools verwendet werden
Erstellen Sie mit Spring Boot 2.0 einen Spring Cloud Config Server mit Sicherheit
Bis Sie ein Spring Boot-Projekt in Intellij erstellen und an Github senden
Aufbau einer Java-Entwicklungsumgebung (Mac + Plejaden All in One Eclipse 4.7 + Spring Boot + Gradle (Buildship))