diff --git a/pom.xml b/pom.xml
index aa4e497844..81ae255005 100644
--- a/pom.xml
+++ b/pom.xml
@@ -614,6 +614,7 @@
spring-5-data-reactive
spring-5-mvc
spring-5-reactive
+ spring-5-reactive-2
spring-5-reactive-client
spring-5-reactive-oauth
spring-5-reactive-security
@@ -826,6 +827,7 @@
spring-5
spring-5-data-reactive
spring-5-reactive
+ spring-5-reactive-2
spring-5-reactive-client
spring-5-reactive-security
spring-5-security
@@ -1286,6 +1288,7 @@
spring-5-data-reactive
spring-5-mvc
spring-5-reactive
+ spring-5-reactive-2
spring-5-reactive-client
spring-5-reactive-oauth
spring-5-reactive-security
diff --git a/spring-5-reactive-2/.gitignore b/spring-5-reactive-2/.gitignore
new file mode 100644
index 0000000000..dec013dfa4
--- /dev/null
+++ b/spring-5-reactive-2/.gitignore
@@ -0,0 +1,12 @@
+#folders#
+.idea
+/target
+/neoDb*
+/data
+/src/main/webapp/WEB-INF/classes
+*/META-INF/*
+
+# Packaged files #
+*.jar
+*.war
+*.ear
\ No newline at end of file
diff --git a/spring-5-reactive-2/README.md b/spring-5-reactive-2/README.md
new file mode 100644
index 0000000000..bbb45e9f8c
--- /dev/null
+++ b/spring-5-reactive-2/README.md
@@ -0,0 +1 @@
+## Spring 5 Reactive Project
diff --git a/spring-5-reactive-2/pom.xml b/spring-5-reactive-2/pom.xml
new file mode 100644
index 0000000000..668e0e5cf9
--- /dev/null
+++ b/spring-5-reactive-2/pom.xml
@@ -0,0 +1,50 @@
+
+
+ 4.0.0
+ com.baeldung
+ spring-5-reactive-2
+ 0.0.1-SNAPSHOT
+ spring-5-reactive-2
+ jar
+ spring 5 sample project about new features
+
+
+ com.baeldung
+ parent-boot-2
+ 0.0.1-SNAPSHOT
+ ../parent-boot-2
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-webflux
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+ provided
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+ com.baeldung.webclient.WebClientApplication
+ JAR
+
+
+
+
+
+
diff --git a/spring-5-reactive-2/src/main/java/com/baeldung/webclient/Tweet.java b/spring-5-reactive-2/src/main/java/com/baeldung/webclient/Tweet.java
new file mode 100644
index 0000000000..8d294955f3
--- /dev/null
+++ b/spring-5-reactive-2/src/main/java/com/baeldung/webclient/Tweet.java
@@ -0,0 +1,13 @@
+package com.baeldung.webclient;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class Tweet {
+ private String text;
+ private String username;
+}
diff --git a/spring-5-reactive-2/src/main/java/com/baeldung/webclient/TweetsSlowServiceController.java b/spring-5-reactive-2/src/main/java/com/baeldung/webclient/TweetsSlowServiceController.java
new file mode 100644
index 0000000000..fecaca25ef
--- /dev/null
+++ b/spring-5-reactive-2/src/main/java/com/baeldung/webclient/TweetsSlowServiceController.java
@@ -0,0 +1,20 @@
+package com.baeldung.webclient;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Arrays;
+import java.util.List;
+
+@RestController
+public class TweetsSlowServiceController {
+
+ @GetMapping("/slow-service-tweets")
+ private List getAllTweets() throws Exception {
+ Thread.sleep(2000L); // delay
+ return Arrays.asList(
+ new Tweet("RestTemplate rules", "@user1"),
+ new Tweet("WebClient is better", "@user2"),
+ new Tweet("OK, both are useful", "@user1"));
+ }
+}
diff --git a/spring-5-reactive-2/src/main/java/com/baeldung/webclient/WebClientApplication.java b/spring-5-reactive-2/src/main/java/com/baeldung/webclient/WebClientApplication.java
new file mode 100644
index 0000000000..751e3a9487
--- /dev/null
+++ b/spring-5-reactive-2/src/main/java/com/baeldung/webclient/WebClientApplication.java
@@ -0,0 +1,11 @@
+package com.baeldung.webclient;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class WebClientApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(WebClientApplication.class, args);
+ }
+}
diff --git a/spring-5-reactive-2/src/main/java/com/baeldung/webclient/WebController.java b/spring-5-reactive-2/src/main/java/com/baeldung/webclient/WebController.java
new file mode 100644
index 0000000000..73f5724819
--- /dev/null
+++ b/spring-5-reactive-2/src/main/java/com/baeldung/webclient/WebController.java
@@ -0,0 +1,60 @@
+package com.baeldung.webclient;
+
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.reactive.function.client.WebClient;
+import reactor.core.publisher.Flux;
+
+import java.util.List;
+
+@Slf4j
+@RestController
+public class WebController {
+
+ private static final int DEFAULT_PORT = 8080;
+
+ @Setter
+ private int serverPort = DEFAULT_PORT;
+
+ @GetMapping("/tweets-blocking")
+ public List getTweetsBlocking() {
+ log.info("Starting BLOCKING Controller!");
+ final String uri = getSlowServiceUri();
+
+ RestTemplate restTemplate = new RestTemplate();
+ ResponseEntity> response = restTemplate.exchange(
+ uri, HttpMethod.GET, null,
+ new ParameterizedTypeReference>(){});
+
+ List result = response.getBody();
+ result.forEach(tweet -> log.info(tweet.toString()));
+ log.info("Exiting BLOCKING Controller!");
+ return result;
+ }
+
+ @GetMapping(value = "/tweets-non-blocking", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
+ public Flux getTweetsNonBlocking() {
+ log.info("Starting NON-BLOCKING Controller!");
+ Flux tweetFlux = WebClient.create()
+ .get()
+ .uri(getSlowServiceUri())
+ .retrieve()
+ .bodyToFlux(Tweet.class);
+
+ tweetFlux.subscribe(tweet -> log.info(tweet.toString()));
+ log.info("Exiting NON-BLOCKING Controller!");
+ return tweetFlux;
+ }
+
+ private String getSlowServiceUri() {
+ return "http://localhost:" + serverPort + "/slow-service-tweets";
+ }
+
+}
diff --git a/spring-5-reactive-2/src/test/java/com/baeldung/webclient/WebControllerIntegrationTest.java b/spring-5-reactive-2/src/test/java/com/baeldung/webclient/WebControllerIntegrationTest.java
new file mode 100644
index 0000000000..09c3a5fb84
--- /dev/null
+++ b/spring-5-reactive-2/src/test/java/com/baeldung/webclient/WebControllerIntegrationTest.java
@@ -0,0 +1,51 @@
+package com.baeldung.webclient;
+
+import org.junit.Before;
+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.boot.web.server.LocalServerPort;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.reactive.server.WebTestClient;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = WebClientApplication.class)
+public class WebControllerIntegrationTest {
+
+ @LocalServerPort
+ int randomServerPort;
+
+ @Autowired
+ private WebTestClient testClient;
+
+ @Autowired
+ private WebController webController;
+
+ @Before
+ public void setup() {
+ webController.setServerPort(randomServerPort);
+ }
+
+ @Test
+ public void whenEndpointWithBlockingClientIsCalled_thenThreeTweetsAreReceived() {
+ testClient.get()
+ .uri("/tweets-blocking")
+ .exchange()
+ .expectStatus()
+ .isOk()
+ .expectBodyList(Tweet.class)
+ .hasSize(3);
+ }
+
+ @Test
+ public void whenEndpointWithNonBlockingClientIsCalled_thenThreeTweetsAreReceived() {
+ testClient.get()
+ .uri("/tweets-non-blocking")
+ .exchange()
+ .expectStatus()
+ .isOk()
+ .expectBodyList(Tweet.class)
+ .hasSize(3);
+ }
+}
\ No newline at end of file