Spring WebFlux is the new module introduced in Spring 5. Spring WebFlux is the first step towards reactive programming model in spring framework.
Spring WebFlux是Spring 5中引入的新模塊。SpringWebFlux是向Spring框架中的React式編程模型邁出的第一步。
If you are new to reactive programming model, then I would highly suggest you to go through following articles to learn about reactive programming.
如果您不熟悉React式編程模型,那么我強烈建議您閱讀以下文章以了解React式編程。
節點式編程、If you are new to Spring 5, please go through Spring 5 Features.
如果您不熟悉Spring 5,請參閱Spring 5功能 。
Spring WebFlux is the alternative to Spring MVC module. Spring WebFlux is used to create fully asynchronous and non-blocking application built on event-loop execution model.
Spring WebFlux是Spring MVC模塊的替代方案。 Spring WebFlux用于創建基于事件循環執行模型的完全異步且非阻塞的應用程序。
Below diagram from Spring Official Documentation provides great insight on comparison of Spring WebFlux to Spring Web MVC.
堆積式編程。 Spring官方文檔中的下圖提供了關于Spring WebFlux與Spring Web MVC比較的深刻見解。
If you are looking to develop a web application or Rest web service on non-blocking reactive model, then you can look into Spring WebFlux.
如果您希望在非阻塞React模型上開發Web應用程序或Rest Web服務,那么可以研究Spring WebFlux。
Spring WebFlux is supported on Tomcat, Jetty, Servlet 3.1+ containers, as well as on non-Servlet runtimes such as Netty and Undertow.
Tomcat,Jetty,Servlet 3.1+容器以及Netty和Undertow等非Servlet運行時都支持Spring WebFlux。
拖放式編程,Spring WebFlux is built on Project Reactor. Project Reactor is the implementation of Reactive Streams specification. Reactor provides two types:
Spring WebFlux基于Project Reactor構建。 Project Reactor是Reactive Streams規范的實現。 Reactor提供兩種類型:
Let’s built a simple Spring WebFlux Hello World application. We will create a simple rest web service and use Spring Boot to run it on default Netty server.
讓我們構建一個簡單的Spring WebFlux Hello World應用程序。 我們將創建一個簡單的rest Web服務,并使用Spring Boot在默認的Netty服務器上運行它。
Our final project structure looks like below image.
Springboot。 我們的最終項目結構如下圖所示。
Let’s look into each component of the application one by one.
讓我們逐一研究應用程序的每個組件。
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.journaldev.spring</groupId><artifactId>SpringWebflux</artifactId><version>0.0.1-SNAPSHOT</version><name>Spring WebFlux</name><description>Spring WebFlux Example</description><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><jdk.version>1.9</jdk.version></properties><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.1.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>io.projectreactor</groupId><artifactId>reactor-test</artifactId><scope>test</scope></dependency></dependencies><repositories><repository><id>spring-snapshots</id><name>Spring Snapshots</name><url>https://repo.spring.io/snapshot</url><snapshots><enabled>true</enabled></snapshots></repository><repository><id>spring-milestones</id><name>Spring Milestones</name><url>https://repo.spring.io/milestone</url><snapshots><enabled>false</enabled></snapshots></repository></repositories><pluginRepositories><pluginRepository><id>spring-snapshots</id><name>Spring Snapshots</name><url>https://repo.spring.io/snapshot</url><snapshots><enabled>true</enabled></snapshots></pluginRepository><pluginRepository><id>spring-milestones</id><name>Spring Milestones</name><url>https://repo.spring.io/milestone</url><snapshots><enabled>false</enabled></snapshots></pluginRepository></pluginRepositories><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins><pluginManagement><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.7.0</version><configuration><source>${jdk.version}</source><target>${jdk.version}</target></configuration></plugin></plugins></pluginManagement></build></project>
The most important dependencies are spring-boot-starter-webflux
and spring-boot-starter-parent
. Some other dependencies are for creating JUnit test cases.
最重要的依賴項是spring-boot-starter-webflux
和spring-boot-starter-parent
。 其他一些依賴關系是用于創建JUnit測試用例的。
Spring源碼,Spring WebFlux Handler method handles the request and returns Mono
or Flux
as response.
Spring WebFlux Handler方法處理請求并返回Mono
或Flux
作為響應。
package com.journaldev.spring.component;import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;import reactor.core.publisher.Mono;@Component
public class HelloWorldHandler {public Mono<ServerResponse> helloWorld(ServerRequest request) {return ServerResponse.ok().contentType(MediaType.TEXT_PLAIN).body(BodyInserters.fromObject("Hello World!"));}
}
Notice that reactive component Mono
holds the ServerResponse
body. Also look at the function chain to set the return content type, response code and body.
注意,React組件Mono
擁有ServerResponse
主體。 還要查看功能鏈,以設置返回內容類型,響應代碼和主體。
Router method are used to define routes for the application. These methods return RouterFunction
object that also holds ServerResponse
body.
java反應式編程, 路由器方法用于定義應用程序的路由。 這些方法返回同樣包含ServerResponse
主體的RouterFunction
對象。
package com.journaldev.spring.component;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;@Configuration
public class HelloWorldRouter {@Beanpublic RouterFunction<ServerResponse> routeHelloWorld(HelloWorldHandler helloWorldHandler) {return RouterFunctions.route(RequestPredicates.GET("/helloWorld").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), helloWorldHandler::helloWorld);}
}
So we are exposing a GET method for /helloWorld
and the client call should accept plain text response.
因此,我們公開了/helloWorld
的GET方法,并且客戶端調用應接受純文本響應。
Let’s configure our simple WebFlux application with Spring Boot.
讓我們使用Spring Boot配置我們的簡單WebFlux應用程序。
package com.journaldev.spring;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
java流式編程。If you look at above code, there is nothing related to Spring WebFlux. But Spring Boot will configure our application as Spring WebFlux since we have added dependency of spring-boot-starter-webflux
module.
如果您看上面的代碼,則與Spring WebFlux沒有任何關系。 但是Spring Boot會將我們的應用程序配置為Spring WebFlux,因為我們添加了spring-boot-starter-webflux
模塊的依賴項。
Our application is ready to execute on Java 8, but if you are using Java 9 then we also need to add module-info.java
class.
我們的應用程序已準備好在Java 8上執行,但是如果您使用的是Java 9,那么我們還需要添加module-info.java
類。
module com.journaldev.spring {requires reactor.core;requires spring.web;requires spring.beans;requires spring.context;requires spring.webflux;requires spring.boot;requires spring.boot.autoconfigure;exports com.journaldev.spring;
}
If you have Spring support in Eclipse, then you can run above class as Spring Boot App.
過程式編程? 如果您在Eclipse中具有Spring支持,則可以在類之上運行Spring Boot App。
If you like to use command line, then open terminal and run command mvn spring-boot:run
from the project source directory.
如果要使用命令行,請打開終端,然后從項目源目錄運行命令mvn spring-boot:run
。
Once the app is running, notice following log messages to make sure everything is good with our app. It’s also helpful when you extend this simple app by adding more routes and functionalities.
應用程序運行后,請注意以下日志消息,以確保我們的應用程序一切正常。 當您通過添加更多路由和功能擴展此簡單應用程序時,它也很有幫助。
2018-05-07 15:01:47.893 INFO 25158 --- [ main] o.s.w.r.f.s.s.RouterFunctionMapping : Mapped ((GET && /helloWorld) && Accept: ) -> com.journaldev.spring.component.HelloWorldRouter$$Lambda$501/704766954@6eeb5d56
2018-05-07 15:01:48.495 INFO 25158 --- [ctor-http-nio-1] r.ipc.netty.tcp.BlockingNettyContext : Started HttpServer on /0:0:0:0:0:0:0:0:8080
2018-05-07 15:01:48.495 INFO 25158 --- [ main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port(s): 8080
2018-05-07 15:01:48.501 INFO 25158 --- [ main] com.journaldev.spring.Application : Started Application in 1.86 seconds (JVM running for 5.542)
函數式編程java。It’s clear from logs that our app is running on Netty server on port 8080. Let’s go ahead and test our application.
從日志中很明顯,我們的應用程序正在端口8080的Netty服務器上運行。讓我們繼續測試我們的應用程序。
We can test our app with various methods.
我們可以通過多種方法測試我們的應用。
$ curl https://localhost:8080/helloWorld
Hello World!
$
使用CURL命令 Here is a JUnit test program to test our Rest web service using WebTestClient
from Spring 5 reactive web.
package com.journaldev.spring;import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SpringWebFluxTest {@Autowiredprivate WebTestClient webTestClient;@Testpublic void testHelloWorld() {webTestClient.get().uri("/helloWorld") // GET method and URI.accept(MediaType.TEXT_PLAIN) //setting ACCEPT-Content.exchange() //gives access to response.expectStatus().isOk() //checking if response is OK.expectBody(String.class).isEqualTo("Hello World!"); // checking for response type and message}}
Spring Framework、Run it a JUnit test case and it should pass with flying colors.
從Spring 5開始使用WebTestClient 這是一個JUnit測試程序,用于使用Spring 5響應式Web中的WebTestClient
測試我們的Rest Web服務。
package com.journaldev.spring;import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SpringWebFluxTest {@Autowiredprivate WebTestClient webTestClient;@Testpublic void testHelloWorld() {webTestClient.get().uri("/helloWorld") // GET method and URI.accept(MediaType.TEXT_PLAIN) //setting ACCEPT-Content.exchange() //gives access to response.expectStatus().isOk() //checking if response is OK.expectBody(String.class).isEqualTo("Hello World!"); // checking for response type and message}}
運行它一個JUnit測試用例,它應該以飛快的速度通過。
We can also use WebClient
to call the REST web service.
package com.journaldev.spring.client;import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;import reactor.core.publisher.Mono;public class HelloWorldWebClient {public static void main(String args[]) {WebClient client = WebClient.create("https://localhost:8080");Mono<ClientResponse> result = client.get().uri("/helloWorld").accept(MediaType.TEXT_PLAIN).exchange();System.out.println("Result = " + result.flatMap(res -> res.bodyToMono(String.class)).block());}}
Just run it as a simple java application and you should see the proper output with a lot of debug messages.
從Spring Web Reactive使用WebClientJava 拖拽式編程 組件? 我們還可以使用WebClient
來調用REST Web服務 。
package com.journaldev.spring.client;import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;import reactor.core.publisher.Mono;public class HelloWorldWebClient {public static void main(String args[]) {WebClient client = WebClient.create("https://localhost:8080");Mono<ClientResponse> result = client.get().uri("/helloWorld").accept(MediaType.TEXT_PLAIN).exchange();System.out.println("Result = " + result.flatMap(res -> res.bodyToMono(String.class)).block());}}
只需將其作為一個簡單的Java應用程序運行即可,您應該看到帶有大量調試消息的正確輸出。
In this post we learned about Spring WebFlux and how to build a hello world reactive Restful web service.
在這篇文章中,我們了解了Spring WebFlux以??及如何構建一個Hello WorldReact式Restful Web服務。
It’s good to see that popular frameworks such as Spring are rooting for reactive programming model. But we have a lot to cover because if all your dependencies are not reactive and non-blocking then your application is also not truly reactive.
webpack的entry選項支持哪些類型、 很高興看到諸如Spring之類的流行框架正在扎根于React式編程模型。 但是我們有很多要討論的內容,因為如果您的所有依賴項都不是React性和非阻塞的,那么您的應用程序也不是真正的React性。
For example, relational database vendors doesn’t have reactive drivers because they depend on JDBC, that is not reactive. Hence Hibernate API is also non-reactive. So if you are using relational databases then you can’t built a truly reactive application, yet. I am hopeful that it will change sooner than later.
例如,關系數據庫供應商沒有響應式驅動程序,因為它們依賴JDBC,而后者不是響應式的。 因此,Hibernate API也是非React性的。 因此,如果您正在使用關系數據庫,那么您還不能構建真正的React式應用程序。 我希望它將早日改變。
Reference: Official Documentation
參考: 官方文檔
拖拽式編程應用軟件開發。翻譯自: https://www.journaldev.com/20763/spring-webflux-reactive-programming
版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。
工作时间:8:00-18:00
客服电话
电子邮件
admin@qq.com
扫码二维码
获取最新动态