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.")
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". (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)
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.
.pathVariable ()
de ServerRequestVous 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));
}
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.
RouterFunctions
.route(GET("/hello/{name}"), req -> ...)
.AndRroute(GET("/hello/hoge"), req -> ...);
-> La variable de chemin a la priorité.
RouterFunctions
.route(GET("/hello/hoge"), req -> ...)
.AndRroute(GET("/hello/{name}"), req -> ...);
-> La définition de chemin fixe a la priorité.
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.
RouterFunction <ServerResponse>
et placez-la dans une autre classeHelloRouter.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.
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
.
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.
@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.
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