[JAVA] Essayez Spring WebFlux (principalement les fonctions de routeur)

Aperçu

Au Java Day Tokyo 2017, j'ai entendu Reactive Web Application by Spring Framework 5.0 et je suis devenu un peu nerveux, donc Spring 5 J'ai essayé Spring WebFlux ajouté à partir de.

Cliquez ici pour les documents de référence. Premier Spring WebFlux (Partie 1 - Essayez Spring WebFlux) L'auteur est Toshiaki Maki, qui est le même que l'orateur. (En fait, au cours de la session, il a dit quelque chose comme "J'écris un blog, donc si vous le lisez, vous pouvez l'essayer.")


Jusqu'à ce que vous démarriez l'application pour le moment

Cette fois, j'ai utilisé Spring Boot 2.0.0 M1. (Parce que Spring Boot prend en charge Spring 5 à partir de 2.0.0)

Créez-le avec Spring Initializer. Définissez la version de Spring Boot sur 2.0.0 M1 et ajoutez "Reactive Web". image.png (Au fait, l'actionneur n'est pas pris en charge au moment de M1. Désolé)

Alors, je l'ai commencé et j'ai confirmé que Netty avait démarré. C'est OK pour le moment. Vous trouverez ci-dessous un extrait du journal de démarrage.

2017-05-20 14:14:17.447  INFO 4880 --- [  restartedMain] o.s.w.r.r.m.a.ControllerMethodResolver   : Looking for @ControllerAdvice: org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext@30361c29: startup date [Sat May 20 14:14:16 JST 2017]; root of context hierarchy
2017-05-20 14:14:17.916  INFO 4880 --- [  restartedMain] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
2017-05-20 14:14:17.944  INFO 4880 --- [  restartedMain] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2017-05-20 14:14:18.241  INFO 4880 --- [  restartedMain] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port(s): 8080
2017-05-20 14:14:18.246  INFO 4880 --- [  restartedMain] itaka.demo.WebfluxSampleApplication      : Started WebfluxSampleApplication in 2.181 seconds (JVM running for 3.946)

Définition du routage avec les fonctions de routeur

Dans WebFlux, s'il existe un @ Bean tel que RouterFunction <ServerResponse>, il sera traité comme une définition de routage. Donc, si vous l'écrivez dans la classe ciblée pour l'analyse des composants, il semble bon n'importe où.

//J'ai des importations statiques, veuillez donc vous référer au matériel de référence pour plus de détails.
@Bean
public RouterFunction<ServerResponse> routes() {
    return route(GET("/"), req -> ok().body(Flux.just("Hello", "WebFlux"), String.class));
}

Ainsi, lorsque je le lance et que j'accède à http: // localhost: 8080 /, "Hello WebFlux" est renvoyé. c'est tout.

Comment gérer PathVariable?

  1. Décrivez comme "{var}" dans l'argument de RequestPredicate ("GET" ou "POST") comme avant
  2. Obtenez avec .pathVariable () de ServerRequest

Vous pouvez suivre la procédure de.

@Bean
public RouterFunction<ServerResponse> routes() {
    return RouterFunctions
            .route(GET("/hello/{name}"), req ->
                    ok().body(Flux.just("Hello", req.pathVariable("name")), String.class));
}

Priorité de routage

Que se passe-t-il si vous définissez à la fois le routage de la variable de chemin ci-dessus et le routage de définition de chemin fixe "/ hello / hoge"? Dès la conclusion, __ le premier est prioritaire __. Facile.

Si vous écrivez d'abord le routage de la variable de chemin

RouterFunctions
 .route(GET("/hello/{name}"), req -> ...)
 .AndRroute(GET("/hello/hoge"), req -> ...);

-> La variable de chemin a la priorité.

Lorsque le routage de la définition de chemin fixe est écrit en premier

RouterFunctions
 .route(GET("/hello/hoge"), req -> ...)
 .AndRroute(GET("/hello/{name}"), req -> ...);

-> La définition de chemin fixe a la priorité.

Si le nombre de définitions de routage augmente

S'il s'agit de l'échelle de l'échantillon, il n'y a pas de problème même si vous connectez la définition de la route comme décrit ci-dessus, mais dans l'application réelle, cela signifie que tout le mappage est décrit dans une classe de contrôleur __ Donc ce n'est pas bon. Par conséquent, vous pouvez écrire un peu proprement en procédant comme suit.

  1. Créez une méthode qui renvoie RouterFunction <ServerResponse> et placez-la dans une autre classe
  2. Appelez la méthode 1 dans la méthode définie d'origine «@ Bean»

HelloRouter.java


@Component
public class HelloRouter {

    private static final String PATH = "/hello";

    public RouterFunction<ServerResponse> route() {
        return RouterFunctions
                .route(GET(PATH), this::hello)
                .andRoute(GET(PATH + "/hoge"), this::helloHoge)
                .andRoute(GET(PATH + "/{name}"), this::helloName);
    }

    private Mono<ServerResponse> hello(ServerRequest req) {
        return ok().body(Flux.just("Hello", "WebFlux"), String.class);
    }

    private Mono<ServerResponse> helloName(ServerRequest req) {
        return ok().body(Flux.just("Hello", req.pathVariable("name")), String.class);
    }

    private Mono<ServerResponse> helloHoge(ServerRequest req) {
        return ok().body(Flux.just("Hoge", "Hoge"), String.class);
    }
}

Route Hello Router()Appel


@Bean
public RouterFunction<ServerResponse> routes(HelloRouter helloRouter) {
    return helloRouter.route();
}

De plus, plusieurs RouterFunction <ServerResponse> peuvent être connectés par une chaîne de méthodes avec .and.

.and()Frotter plusieurs fonctions de routeur avec


//Dans StreamRouter"/strem"On suppose que l'acheminement de
@Bean
public RouterFunction<ServerResponse> routes(HelloRouter helloRouter, StreamRouter streamRouter) {
    return helloRouter.route()
            .and(streamRouter.route());
}

Cela définit le routage suivant.

(Ajout) Amélioration par RouterFunctions.nest ()

Commentaires, alors essayez de réécrire le code ci-dessus en utilisant nest (). (Merci à Maki!)

RouterFunctions.nest()Définition du routage hiérarchique


public RouterFunction<ServerResponse> routes() {
    return nest(path("/hello"),
            route(GET("/"), this::hello)
                .andRoute(GET("/hoge"), this::helloHoge)
                .andRoute(GET("/{name}"), this::helloName));
}

Au fait, j'ai également importé statiquement RouterFunctions.route (), donc c'était très rafraîchissant! Puisque vous pouvez comprendre le contenu du routage uniquement en regardant la partie Fonction du routeur, c'est aussi un meilleur endroit que la définition dans @ Controller.


Jouez avec Infinite Stream

Le Flux défini dans` .body () ʻ de ServerResponse est une classe qui implémente Publisher of Reactive Stream, et il semble que vous puissiez réaliser un Creative Stream avec un bon feeling.

À titre d'exemple concret, implémentons quelque chose qui "lorsque vous y accédez, les nombres sont renvoyés à l'infini et les nombres sont comptés". La méthode est la suivante.

  1. Créez un flux infini
  2. Créer du flux à partir d'un flux
  3. Définissez 2 Flux comme corps
@Bean
public RouterFunction<ServerResponse> routes() {
    Stream<Integer> stream = Stream.iterate(0, i -> i + 1);
    Flux<Integer> flux = Flux.fromStream(stream).delayElements(Duration.ofSeconds(1));

    return RouterFunctions
            .route(GET("/stream"), req ->
                    ok().contentType(MediaType.APPLICATION_STREAM_JSON).body(flux, Integer.class));
}

Maintenant, lorsque vous accédez à http: // localhost: 8080 / stream, les nombres couleront à l'infini. Cependant, tel quel, il coule avec une grande impulsion, donc dans l'exemple ci-dessus, .delayElements () est utilisé pour le faire couler avec un intervalle.


Résumé

En disant "essayez WebFlux", j'ai fini par expérimenter plus de la moitié des fonctions du routeur. Pour faire l'expérience de "Web Flux is amazing", il semble préférable de créer une application qui peut être comprise comme étant compliquée ou "super rapide parce qu'elle est non bloquante".

Router Functiuons était plus excitant que lorsque j'écoutais la session Java Day Tokyo. J'ai utilisé uniquement GET cette fois, mais bien sûr, d'autres HttpMethods peuvent être utilisées, et des conditions de routage complexes peuvent être créées en utilisant .and (), .or (), .negate (), etc. Cela a l'air amusant parce que vous pouvez aussi le faire. Cependant, pour le moment (Spring Boot 2.0.0), il semble qu'il ne puisse pas coexister avec @ Controller, il est donc un peu difficile de l'appliquer à des applications existantes (toutes doivent être réécrites). Si vous le faites, vous devriez le faire avec une nouvelle application.

Le code de ce que j'ai essayé cette fois est le suivant. (Depuis que j'ai refactoré en écrivant, il y a un léger écart par rapport au code de cet article) IsaoTakahashi/webflux-sample - GitHub

Recommended Posts

Essayez Spring WebFlux (principalement les fonctions de routeur)
Essayez le tutoriel Spring WebFlux
Essayez d'utiliser Spring JDBC
Essayez Spring Boot de 0 à 100.
Essayez d'implémenter une session WebFlux
Essayez d'utiliser Spring Boot Security
Essayez d'implémenter un filtre WebFlux
Essayez Spring Boot sur Mac