Feing client vs web client (#12968)
* implement code example for feignClient vs WebClient * refactor code example for feignClient vs WebClient with /products endpoint * fix PR comment
This commit is contained in:
parent
f6ae9ceefa
commit
28c0b9569e
|
@ -20,6 +20,14 @@
|
|||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectreactor</groupId>
|
||||
<artifactId>reactor-spring</artifactId>
|
||||
|
@ -35,10 +43,27 @@
|
|||
<artifactId>reactor-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-dependencies</artifactId>
|
||||
<version>${spring-cloud.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<properties>
|
||||
<reactor-spring.version>1.0.1.RELEASE</reactor-spring.version>
|
||||
<spring-cloud.version>2021.0.4</spring-cloud.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,13 @@
|
|||
package com.baeldung.webclient;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class Product {
|
||||
private String title;
|
||||
private String description;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.baeldung.webclient;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
@FeignClient(value = "productsBlocking", url = "http://localhost:8080")
|
||||
public interface ProductsFeignClient {
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/slow-service-products", produces = "application/json")
|
||||
List<Product> getProductsBlocking(URI baseUrl);
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package com.baeldung.webclient;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class ProductsSlowServiceController {
|
||||
|
||||
@GetMapping("/slow-service-products")
|
||||
private List<Product> getAllProducts() throws InterruptedException {
|
||||
Thread.sleep(2000L); // delay
|
||||
return Arrays.asList(
|
||||
new Product("Fancy Smartphone", "A stylish phone you need"),
|
||||
new Product("Cool Watch", "The only device you need"),
|
||||
new Product("Smart TV", "Cristal clean images")
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.baeldung.webclient;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableFeignClients
|
||||
public class WebClientApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(WebClientApplication.class, args);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
package com.baeldung.webclient;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class WebController {
|
||||
|
||||
private static final int DEFAULT_PORT = 8080;
|
||||
|
||||
public static final String SLOW_SERVICE_PRODUCTS_ENDPOINT_NAME = "/slow-service-products";
|
||||
|
||||
@Setter
|
||||
private int serverPort = DEFAULT_PORT;
|
||||
|
||||
@Autowired
|
||||
private ProductsFeignClient productsFeignClient;
|
||||
|
||||
@GetMapping("/products-blocking")
|
||||
public List<Product> getProductsBlocking() {
|
||||
log.info("Starting BLOCKING Controller!");
|
||||
final URI uri = URI.create(getSlowServiceBaseUri());
|
||||
|
||||
List<Product> result = productsFeignClient.getProductsBlocking(uri);
|
||||
result.forEach(product -> log.info(product.toString()));
|
||||
log.info("Exiting BLOCKING Controller!");
|
||||
return result;
|
||||
}
|
||||
|
||||
@GetMapping(value = "/products-non-blocking", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
||||
public Flux<Product> getProductsNonBlocking() {
|
||||
log.info("Starting NON-BLOCKING Controller!");
|
||||
Flux<Product> productFlux = WebClient.create()
|
||||
.get()
|
||||
.uri(getSlowServiceBaseUri() + SLOW_SERVICE_PRODUCTS_ENDPOINT_NAME)
|
||||
.retrieve()
|
||||
.bodyToFlux(Product.class);
|
||||
|
||||
productFlux.subscribe(product -> log.info(product.toString()));
|
||||
log.info("Exiting NON-BLOCKING Controller!");
|
||||
return productFlux;
|
||||
}
|
||||
|
||||
private String getSlowServiceBaseUri() {
|
||||
return "http://localhost:" + serverPort;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package databuffer;
|
||||
package com.baeldung.databuffer;
|
||||
|
||||
import com.baeldung.databuffer.DataBufferToInputStream;
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
package com.baeldung.webclient;
|
||||
|
||||
import static org.springframework.test.annotation.DirtiesContext.ClassMode.BEFORE_CLASS;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.server.LocalServerPort;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
@DirtiesContext(classMode = BEFORE_CLASS)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = WebClientApplication.class)
|
||||
class WebControllerIntegrationTest {
|
||||
|
||||
@LocalServerPort
|
||||
private int randomServerPort;
|
||||
|
||||
@Autowired
|
||||
private WebTestClient testClient;
|
||||
|
||||
@Autowired
|
||||
private WebController webController;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
webController.setServerPort(randomServerPort);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenEndpointWithBlockingClientIsCalled_thenThreeProductsAreReceived() {
|
||||
testClient.get()
|
||||
.uri("/products-blocking")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBodyList(Product.class).hasSize(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenEndpointWithNonBlockingClientIsCalled_thenThreeProductsAreReceived() {
|
||||
testClient.get()
|
||||
.uri("/products-non-blocking")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBodyList(Product.class).hasSize(3);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue