[JAVA] Spring Boot 2.2 prend désormais en charge RSocket, alors essayez-le

Bonjour. Spring Boot 2.2 prend désormais en charge RSocket, alors je l'ai essayé.

Qu'est-ce que RSocket?

Comparaison avec d'autres protocoles

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.

Je vais l'essayer immédiatement

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.

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

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.

Structure du projet

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!

Flux_demo.gif

Résumé

référence

Recommended Posts

Spring Boot 2.2 prend désormais en charge RSocket, alors essayez-le
Qu'est-ce que @Autowired dans Spring Boot?
Qu'est-ce qu'un fichier .original Spring Boot?
Exécuter un projet Spring Boot avec VS Code
Comment ajouter un chemin de classe dans Spring Boot
Conseils Java - Créez un projet Spring Boot avec Gradle
Lorsque je soutiens l'internationalisation avec Spring Boot, je suis accro à ne pas traduire une langue spécifique
Jusqu'à ce que vous créiez un projet Spring Boot dans Intellij et que vous le transmettiez à Github
Comment créer un projet Spring Boot dans IntelliJ
Essayez gRPC dans le projet Spring Boot et Spring Cloud (Mac OS)
Définir le paramètre contextuel dans Spring Boot
Multi-projets Spring Boot 2 avec Gradle
Changements majeurs dans Spring Boot 1.5
NoHttpResponseException dans Spring Boot + WireMock
Essayez d'utiliser Spring Boot Security
Essayez Spring Boot sur Mac
Obtenez une instance proxy du composant lui-même dans Spring Boot
Partie 1: Essayez d'utiliser la connexion OAuth 2.0 prise en charge par Spring Security 5 avec Spring Boot
Intégré dans Spring Boot à l'aide d'un fichier de définition de bean nommé application.xml
Écrivons un code de test pour la fonction de connexion avec Spring Boot
[Spring Boot] Jusqu'à ce que @Autowired soit exécuté dans la classe de test [JUnit5]
Spring Boot Hello World dans Eclipse
Développement d'applications Spring Boot dans Eclipse
Écrire du code de test avec Spring Boot
Qu'est-ce qu'un extrait de code en programmation?
Implémenter l'API REST avec Spring Boot
Le traitement des événements est effectué au printemps.
Implémenter l'application Spring Boot dans Gradle
Essayez d'exécuter Spring Boot sur Kubernetes
Un mémo qui a touché Spring Boot
Comment utiliser Thymeleaf avec Spring Boot
Spring.messages.fallback-to-system-locale: false est requis pour le message par défaut.properties pour la prise en charge i18n de Spring Boot
Créez un projet Spring Boot avec intellij et quittez immédiatement après le lancement
Une histoire sur un projet Spring Boot écrit en Java qui prend en charge Kotlin
Les champs auto-câblés dans une classe qui hérite de TextWebSocketHandler dans Spring Boot deviennent NULL
Mémo: [Java] Si un fichier se trouve dans le répertoire surveillé, traitez-le.
Déployer automatiquement des applications Web développées en Java à l'aide de Jenkins [Spring Boot App Edition]
Lorsque j'ai défini un bean de portée de session dans Spring Boot, il se comportait étrangement et devait être ajusté.
Un super débutant a terminé le livre d'introduction du printemps, je vais donc le résumer à ma manière