Hallo. Spring Boot 2.2 unterstützt jetzt RSocket, also habe ich es versucht.
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.
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.
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.
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!
Recommended Posts