[JAVA] Spring Boot 2.2 unterstützt jetzt RSocket. Probieren Sie es aus

Hallo. Spring Boot 2.2 unterstützt jetzt RSocket, also habe ich es versucht.

Was ist RSocket?

Vergleich mit anderen Protokollen

vs REST --RSocket hat weniger Kommunikationsaufwand als REST.

vs gRPC --gRPC unterstützt keine Kommunikation mit Browsern. Wenn Sie mit einem Browser kommunizieren möchten, benötigen Sie einen Proxy, um in REST zu konvertieren.

Weitere Informationen finden Sie auf der folgenden Website.

Ich werde es sofort versuchen

Nachdem ich beim Betrachten der offiziellen Website einen groben Überblick habe, werde ich eine einfache Anwendung erstellen. Da RSocket ein Kommunikationsprotokoll zwischen Diensten ist

Du brauchst zwei. Erstellen Sie sowohl rsocket-client als auch rsocket-backend als Server und versuchen Sie vorerst die Kommunikation zwischen den Servern. Das Sequenzdiagramm der Anwendung ist wie folgt.

スクリーンショット 2020-01-08 22.20.47.png

Ich wollte mit einem Browser darauf zugreifen und die Ergebnisse sehen, daher ist rsocket-client eine Anwendung mit einem HTTP-Endpunkt. 1-4 sind "Request-Response" -Interaktionen und 5-9 sind "Request-Stream" -Interaktionen. Ich habe SSE (Server-Sent Events) verwendet, weil ich wollte, dass die Antwort von 9 jederzeit zurückgegeben wird.

Projektstruktur

Erstellen Sie rsocket-client bzw. rsocket-backend als Teilprojekte. Außerdem wollte ich nicht das Datenmodell (DTO) definieren, das für die Anforderung und Antwort in jedem Projekt verwendet wird, daher werde ich dies auch im Teilprojekt (rsocket-model) erstellen.

|- build.gradle
|- rsocket-model/
|  |- build.gradle
|  :
|- rsocket-client/
|  |- build.gradle
|  :
└  rsocket-backend/
   |- build.gradle
   :

Das übliche build.gradle sieht so aus. Fügen Sie der Abhängigkeit "Spring-Boot-Starter-Rsocket" und "Spring-Boot-Starter-Webflux" hinzu.

build.gradle


buildscript {
	repositories {
		mavenCentral()
		maven { url "https://plugins.gradle.org/m2/" }
	}

	dependencies {
		classpath "org.springframework.boot:spring-boot-gradle-plugin:2.2.2.RELEASE"
		classpath "io.spring.gradle:dependency-management-plugin:1.0.8.RELEASE"
	}
}

allprojects {
	repositories {
		mavenCentral()
	}
}

subprojects {
	group = 'sandbox'
	version = '0.0.1-SNAPSHOT'

	apply plugin: "java"
	apply plugin: "java-library"
	apply plugin: "org.springframework.boot"
	apply plugin: "io.spring.dependency-management"

	sourceCompatibility = JavaVersion.VERSION_11
	targetCompatibility = JavaVersion.VERSION_11

	dependencyManagement {
		dependencies {
			dependency "org.springframework.boot:spring-boot-starter-rsocket:2.2.2.RELEASE"
			dependency "org.springframework.boot:spring-boot-starter-webflux:2.2.2.RELEASE"
			dependency "org.springframework.boot:spring-boot-devtools:2.2.2.RELEASE"
		}
	}
}

rsocket-model build.gradle von rsocket-model.

build.gradle


project(":rsocket-model") {
    dependencies {
        compileOnly("org.projectlombok:lombok")
        annotationProcessor("org.projectlombok:lombok")
    }
    bootJar {
        enabled = false
    }
    jar {
        enabled = true
    }
}

Definition von DTO für die Anfrage. Es scheint, dass Jackson zum Codieren und Decodieren von Java-Objekten verwendet wird. Vergessen Sie also nicht, einen Standardkonstruktor zu erstellen.

RequestData.java


package sandbox.rsocket;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@NoArgsConstructor
@AllArgsConstructor
@Data
public class RequestData {
    String message;
}

Definition von DTO für die Antwort.

ResponseData.java


package sandbox.rsocket;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@NoArgsConstructor
@AllArgsConstructor
@Data
public class ResponseData {
    String message;
}

rsocket-bankend rsocket-bankend build.gradle.

rsocket-bankend/build.gradle


project(":rsocket-backend") {
    dependencies {
        implementation project(':rsocket-model')
        implementation 'org.springframework.boot:spring-boot-starter-rsocket'
        implementation 'org.springframework.boot:spring-boot-starter-webflux'
        implementation 'org.springframework.boot:spring-boot-devtools'

        compileOnly("org.projectlombok:lombok")
        annotationProcessor("org.projectlombok:lombok")
    }
}

Geben Sie die Portnummer (7000) an, die von RSocket in application.yml verwendet wird. Sie können auch das Transportprotokoll von YAML angeben. Die Definition dieses Bereichs finden Sie in der Spring Boot-Dokumentation. 8.2. RSocket server Auto-configuration

application.yml


spring:
  rsocket:
    server:
      port: 7000
      # Remove commented out if enable RSocket over websocket. (Using tcp as default.)
      # See the link for the details. https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/html/spring-boot-features.html#boot-features-rsocket-strategies-auto-configuration
      # mapping-path: /rsocket
      # transport: websocket

RSocket Server Controller Definition. Legen Sie den RSocket-Endpunktnamen mit der Annotation "@ MessageMapping" fest. Da "getMono" einzelne Daten zurückgibt, geben "Mono" und "getFlux" mehrere Daten (Stream) zurück, sodass die Antwort in "Flux" gespeichert wird.

RSocketServerController.java


package sandbox.rsocket;

import java.time.Duration;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.stereotype.Controller;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@Slf4j
@AllArgsConstructor
@Controller
public class RSocketServerController {
    /**
     * Get response data with mono.
     */
    @MessageMapping("getMono")
    public Mono<ResponseData> getMono(RequestData requestData) {
        log.info("Calling getMono method. request={}", requestData);
        return Mono.just(new ResponseData(requestData.getMessage()));
    }

    /**
     * Get response data with flux.
     * Responds one of the response data every seconds.
     */
    @MessageMapping("getFlux")
    public Flux<ResponseData> getFlux(RequestData requestData) {
        log.info("Calling getFlux method. request={}", requestData);
        final List<ResponseData> list =
                IntStream.rangeClosed(1, 10)
                         .boxed()
                         .map(i -> new ResponseData(requestData.getMessage() + '_' + i))
                         .collect(Collectors.toList());
        return Flux.fromIterable(list)
                   .delayElements(Duration.ofSeconds(1));
    }
}

RSocket-client

build.gradle von rsocket-client.

rsocket-client/build.gradle


project(":rsocket-client") {
    dependencies {
        implementation project(':rsocket-model')
        implementation 'org.springframework.boot:spring-boot-starter-rsocket'
        implementation 'org.springframework.boot:spring-boot-starter-webflux'
        implementation 'org.springframework.boot:spring-boot-devtools'

        compileOnly("org.projectlombok:lombok")
        annotationProcessor("org.projectlombok:lombok")
    }
}

Geben Sie in application.yml die Portnummer (8081) des HTTP-Endpunkts an. Übrigens, wenn Sie die Protokollstufe auf der Clientseite auf DEBUG setzen, können Sie die Frame-Informationen von RSocket an die Konsole ausgeben.

application.yml


server:
  port: 8081
# Remove commented out if u want to see RSocket frame on console log.
# logging:
#  level:
#    root: DEBUG

Das Folgende ist die DEBUG-Protokollausgabe an die Konsole, wenn "getMono" angefordert wird. Sie können ein solches Protokoll sehen!

2020-01-08 23:15:00.853 DEBUG 6776 --- [ctor-http-nio-2] o.s.http.codec.cbor.Jackson2CborEncoder  : Encoding [RequestData(message=test)]
2020-01-08 23:15:00.879 DEBUG 6776 --- [actor-tcp-nio-1] io.rsocket.FrameLogger                   : sending -> 
Frame => Stream ID: 1 Type: REQUEST_RESPONSE Flags: 0b100000000 Length: 36
Metadata:
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| fe 00 00 08 07 67 65 74 4d 6f 6e 6f             |.....getMono    |
+--------+-------------------------------------------------+----------------+
Data:
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| bf 67 6d 65 73 73 61 67 65 64 74 65 73 74 ff    |.gmessagedtest. |
+--------+-------------------------------------------------+----------------+
2020-01-08 23:15:01.015 DEBUG 6776 --- [actor-tcp-nio-1] io.rsocket.FrameLogger                   : receiving -> 
Frame => Stream ID: 1 Type: NEXT_COMPLETE Flags: 0b1100000 Length: 21
Data:
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| bf 67 6d 65 73 73 61 67 65 64 74 65 73 74 ff    |.gmessagedtest. |
+--------+-------------------------------------------------+----------------+
2020-01-08 23:15:01.023 DEBUG 6776 --- [actor-tcp-nio-1] o.s.http.codec.cbor.Jackson2CborDecoder  : Decoded [ResponseData(message=test)]
2020-01-08 23:15:01.023 DEBUG 6776 --- [actor-tcp-nio-1] o.s.http.codec.json.Jackson2JsonEncoder  : [e539e702] Encoding [ResponseData(message=test)]

Konfigurationsdefinition für den Client. Stellen Sie den Hostnamen (localhost) und die Portnummer (7000) des RSocket-Servers in "RSocketRequester" ein. Die Builder-Klasse wird bereitgestellt, sodass Sie sie in wenigen Zeilen schreiben können.

ClientConfiguration.java


package sandbox.rsocket;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.rsocket.RSocketRequester;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@AllArgsConstructor
@Configuration
public class ClientConfiguration {
    private final RSocketRequester.Builder builder;

    @Bean
    public RSocketRequester rSocketRequester() {
        return builder.connectTcp("localhost", 7000)
                      .doOnNext(socket -> log.info("Connected to RSocket."))
                      .block();
    }
}

Definition der RSocket-Client-Serviceklasse. Hier wird der Endpunktname des RSocket-Servers festgelegt.

RSocketClientService.java


package sandbox.rsocket;

import org.springframework.messaging.rsocket.RSocketRequester;
import org.springframework.stereotype.Service;

import lombok.AllArgsConstructor;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@AllArgsConstructor
@Service
public class RSocketClientService {
    private final RSocketRequester rSocketRequester;

    public Mono<ResponseData> getMono(RequestData data) {
        return rSocketRequester.route("getMono")
                               .data(data)
                               .retrieveMono(ResponseData.class);
    }

    public Flux<ResponseData> getFlux(RequestData data) {
        return rSocketRequester.route("getFlux")
                               .data(data)
                               .retrieveFlux(ResponseData.class);
    }
}

Definition des HTTP-Endpunkts für den RSocket-Client.

RSocketClientController.java


package sandbox.rsocket;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import lombok.AllArgsConstructor;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@AllArgsConstructor
@RestController
public class RSocketClientController {
    private final RSocketClientService clientService;

    /**
     * Get response mono data.
     */
    @GetMapping("/mono")
    public Mono<ResponseData> mono(@RequestParam String message) {
        return clientService.getMono(new RequestData(message));
    }

    /**
     * Get response flux data with server sent events.
     */
    @GetMapping(produces = MediaType.TEXT_EVENT_STREAM_VALUE, value = "/flux")
    public Flux<ResponseData> flux(@RequestParam String message) {
        return clientService.getFlux(new RequestData(message));
    }
}

Booten Sie rsocket-bankend bzw. rsocket-client, um auf den HTTP-Endpunkt zuzugreifen. Das Folgende ist das Ergebnis beim Zugriff auf "http: // localhost: 8081 / flow". Daten werden jede Sekunde beantwortet!

Flux_demo.gif

Zusammenfassung

Referenz

Recommended Posts

Spring Boot 2.2 unterstützt jetzt RSocket. Probieren Sie es aus
Was ist @Autowired im Spring Boot?
Was ist eine Spring Boot-Originaldatei?
Führen Sie ein Spring Boot-Projekt mit VS-Code aus
So fügen Sie in Spring Boot einen Klassenpfad hinzu
Java-Tipps - Erstellen Sie mit Gradle ein Spring Boot-Projekt
Wenn ich die Internationalisierung mit Spring Boot unterstütze, bin ich süchtig danach, kein bestimmtes Gebietsschema zu übersetzen
Bis Sie ein Spring Boot-Projekt in Intellij erstellen und an Github senden
So erstellen Sie ein Spring Boot-Projekt in IntelliJ
Probieren Sie gRPC im Spring Boot & Spring Cloud-Projekt (Mac OS) aus.
Legen Sie den Kontextparameter in Spring Boot fest
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
Versuchen Sie Spring Boot auf dem Mac
Rufen Sie in Spring Boot eine Proxy-Instanz der Komponente selbst ab
Teil 1: Versuchen Sie, die von Spring Security 5 unterstützte OAuth 2.0-Anmeldung mit Spring Boot zu verwenden
Wird in Spring Boot mithilfe einer Bean-Definitionsdatei mit dem Namen application.xml angepasst
Schreiben wir einen Testcode für die Anmeldefunktion mit Spring Boot
[Spring Boot] Bis @Autowired in der Testklasse [JUnit5] ausgeführt wird
Frühlingsstiefel Hallo Welt in Eclipse
Spring Boot-Anwendungsentwicklung in Eclipse
Schreiben Sie den Testcode mit Spring Boot
Was ist ein Ausschnitt in der Programmierung?
Implementieren Sie die REST-API mit Spring Boot
Die Ereignisverarbeitung wird im Frühjahr durchgeführt.
Implementieren Sie die Spring Boot-Anwendung in Gradle
Versuchen Sie, Spring Boot auf Kubernetes auszuführen
Ein Memo, das Spring Boot berührte
Verwendung von Thymeleaf mit Spring Boot
Spring.messages.fallback-to-system-locale: false ist erforderlich, um message.properties für die i18n-Unterstützung von Spring boot als Standard festzulegen
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
Autowired-Felder in einer Klasse, die TextWebSocketHandler in Spring Boot erbt, werden NULL
Anmerkung: [Java] Wenn sich eine Datei im überwachten Verzeichnis befindet, verarbeiten Sie sie.
Automatische Bereitstellung von in Java entwickelten Webanwendungen mit Jenkins [Spring Boot App Edition]
Als ich in Spring Boot eine Sitzungsbereichs-Bean definierte, verhielt sie sich seltsam und musste angepasst werden.
Ein Super-Anfänger hat das Frühlings-Einführungsbuch fertiggestellt, daher werde ich es auf meine eigene Weise zusammenfassen