Bonjour. Spring Boot 2.2 prend désormais en charge RSocket, alors je l'ai essayé.
vs REST --RSocket a moins de surcharge de communication que REST.
vs gRPC --gRPC ne prend pas en charge la communication avec les navigateurs. Si vous souhaitez communiquer avec un navigateur, vous avez besoin d'un proxy pour convertir en REST.
Pour plus de détails, consultez le site suivant.
Maintenant que j'ai un aperçu approximatif en regardant le site officiel, je vais créer une application simple. Puisque RSocket est un protocole de communication entre les services
--Expéditeur de la demande (rsocket-client)
Vous en avez besoin de deux. Créez à la fois rsocket-client et rsocket-backend en tant que serveurs et, pour le moment, essayez la communication entre les serveurs. Le diagramme de séquence de l'application est le suivant.
Je voulais y accéder avec un navigateur et voir les résultats, donc rsocket-client est une application avec un point de terminaison HTTP. 1-4 sont des interactions "demande-réponse" et 5-9 sont des interactions "demande-flux". J'ai utilisé SSE (Server-Sent Events) parce que je voulais que la réponse de 9 soit renvoyée à tout moment.
Créez respectivement rsocket-client et rsocket-backend en tant que sous-projets. De plus, je ne voulais pas définir le modèle de données (DTO) utilisé pour la demande et la réponse dans chaque projet, donc je vais également le créer dans le sous-projet (rsocket-model).
|- build.gradle
|- rsocket-model/
| |- build.gradle
| :
|- rsocket-client/
| |- build.gradle
| :
└ rsocket-backend/
|- build.gradle
:
Le build.gradle commun ressemble à ceci.
Ajoutez spring-boot-starter-rsocket
et spring-boot-starter-webflux
à la dépendance.
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 de rsocket-model.
build.gradle
project(":rsocket-model") {
dependencies {
compileOnly("org.projectlombok:lombok")
annotationProcessor("org.projectlombok:lombok")
}
bootJar {
enabled = false
}
jar {
enabled = true
}
}
Définition du DTO pour la demande. Il semble que Jackson soit utilisé pour encoder et décoder des objets Java, alors n'oubliez pas de créer un constructeur par défaut.
RequestData.java
package sandbox.rsocket;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Data
public class RequestData {
String message;
}
Définition du DTO pour la réponse.
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")
}
}
Spécifiez le numéro de port (7000) utilisé par RSocket dans application.yml. Vous pouvez également spécifier le protocole de transport de YAML. La définition de cette zone se trouve dans la documentation de Spring Boot. 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
Définition du contrôleur de serveur RSocket.
Définissez le nom du point de terminaison RSocket avec l'annotation @ MessageMapping
.
Puisque getMono
renvoie une seule donnée, Mono
et getFlux
renvoient plusieurs données (flux), la réponse est donc stockée dans Flux
.
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 de 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")
}
}
Dans application.yml, spécifiez le numéro de port (8081) du point de terminaison HTTP. En passant, si vous définissez le niveau de journalisation du côté client sur DEBUG, vous pouvez envoyer les informations de trame de RSocket à la console.
application.yml
server:
port: 8081
# Remove commented out if u want to see RSocket frame on console log.
# logging:
# level:
# root: DEBUG
Ce qui suit est la sortie du journal DEBUG vers la console lors de la demande de getMono
. Vous pouvez voir un journal comme ça!
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)]
Définition de la configuration pour le client. Définissez le nom d'hôte (localhost) et le numéro de port (7000) du serveur RSocket dans RSocketRequester
. La classe Builder est fournie, vous pouvez donc l'écrire en quelques lignes.
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();
}
}
Définition de la classe de service client RSocket. Le nom du point de terminaison du serveur RSocket est défini ici.
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);
}
}
Définition du point de terminaison HTTP pour le client RSocket.
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));
}
}
BootRun rsocket-bankend et rsocket-client respectivement pour accéder au point de terminaison HTTP.
Voici le résultat lors de l'accès à http: // localhost: 8081 / flux
. Les données sont répondues chaque seconde!
Recommended Posts