I am trying to run a spring-bot micro-service using netflix-eureka and webflux and I have the following problem:
When I try to launch a request using webClient on one of my other micro-service it fails but it works with rest template.
My pom.xml :
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.my.company.invoise</groupId>
<artifactId>invoice</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>invoice</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
<spring-cloud.version>2020.0.0</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate5</artifactId>
</dependency>
<dependency>
<groupId>com.mycompany.invoise</groupId>
<artifactId>core</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
My run file (InvoiceApplication.java) :
@SpringBootApplication
@EntityScan("com.mycompany.invoise.core.entity.invoice")
public class InvoiceApplication {
public static void main(String[] args) {
SpringApplication.run(InvoiceApplication.class, args);
}
@Bean
public Hibernate5Module dataTypeHibernateModule(){
Hibernate5Module module = new Hibernate5Module();
module.disable(Hibernate5Module.Feature.USE_TRANSIENT_ANNOTATION);
module.enable(Hibernate5Module.Feature.SERIALIZE_IDENTIFIER_FOR_LAZY_NOT_LOADED_OBJECTS);
return module;
}
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
@Bean
@LoadBalanced
public WebClient.Builder getWebClientBuilder(){
return WebClient.builder();
}
}
My API (InvoiceRessource.java) :
@RestController
@RequestMapping("/invoice")
public class InvoiceResource {
@Autowired
private IInvoiceService invoiceService ;
@Autowired
private RestTemplate restTemplate ;
@Autowired
private WebClient.Builder wBuilder ;
public IInvoiceService getInvoiceService() {
return invoiceService;
}
public void setInvoiceService(IInvoiceService invoiceService) {
this.invoiceService = invoiceService;
}
@PostMapping("")
public Invoice create(@RequestBody Invoice invoice){
invoiceService.createInvoice(invoice);
return invoice ;
}
@GetMapping("")
public ParallelFlux<Invoice> list(){
System.out.println("You just called list method");
Iterable<Invoice> invoices = invoiceService.getInvoiceList();
List<Mono<Invoice>> invoiceMonos = new ArrayList<>();
final WebClient webClient = wBuilder.baseUrl("http://customer-service").build();
invoices.forEach(invoice ->
//{
invoiceMonos.add(webClient.get()
.uri("/customer/" + invoice.getIdCustomer())
.retrieve()
.bodyToMono(Customer.class)
.map(customer -> {
invoice.setCustomer(customer);
return invoice ;
}))
// invoice.setCustomer(restTemplate.getForObject(
// "http://customer-service/customer/" + invoice.getIdCustomer(),
// Customer.class
// ));}
// This version works !
);
Flux<Invoice> invoiceFlux = Flux.concat(invoiceMonos);
return invoiceFlux.parallel().runOn(Schedulers.boundedElastic());
//return invoices ;
}
@GetMapping("/{id}")
public @ResponseBody Invoice displayInvoice(@PathVariable("id") String number){
System.out.println("displayInvoice had been called");
Invoice invoice = invoiceService.getInvoiceByNumber(number);
Customer customer = restTemplate.getForObject(
"http://customer-service/customer/" + invoice.getIdCustomer(),
Customer.class);
customer.setAddress(restTemplate.getForObject(
"http://customer-service/address/" + customer.getAddress().getId(),
Address.class));
invoice.setCustomer(customer);
return invoice ;
}
public RestTemplate getRestTemplate() {
return restTemplate;
}
public void setRestTemplate(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public WebClient.Builder getwBuilder() {
return wBuilder;
}
public void setwBuilder(WebClient.Builder wBuilder) {
this.wBuilder = wBuilder;
}
}
Entity File (Customer.java):
@Entity
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false,length = 50)
private String name;
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL,orphanRemoval = true,optional = false)
@JoinColumn(name="ID_ADDRESS")
private Address address;
public Customer(String name) {
this.name = name;
}
public Customer() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
Logs (Debug mode activated):
2021-01-23 23:07:22.886 DEBUG 2244 --- [p-nio-80-exec-9] o.s.web.servlet.DispatcherServlet :
GET "/home", parameters={}
2021-01-23 23:07:22.886 DEBUG 2244 --- [p-nio-80-exec-9] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to com.my.company.invoise.invoice.controller.InvoiceControllerWeb#displayWhom(Model)
You just called displayWhom
2021-01-23 23:07:22.886 DEBUG 2244 --- [p-nio-80-exec-9] o.s.w.s.v.ContentNegotiatingViewResolver : Selected 'text/html' given [text/html, application/xhtml+xml, image/webp, application/xml;q=0.9, */*;q=0.8]
2021-01-23 23:07:22.886 DEBUG 2244 --- [p-nio-80-exec-9] o.s.web.servlet.DispatcherServlet : Completed 200 OK
2021-01-23 23:07:22.933 DEBUG 2244 --- [-nio-80-exec-10] o.s.web.servlet.DispatcherServlet : GET "/js/script.js", parameters={}
2021-01-23 23:07:22.933 DEBUG 2244 --- [-nio-80-exec-10] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped to ResourceHttpRequestHandler [class path resource [META-INF/resources/], class path resource [resources/], class path resource [static/], class path resource [public/], ServletContext resource [/]]
2021-01-23 23:07:22.933 DEBUG 2244 --- [-nio-80-exec-10] o.s.web.servlet.DispatcherServlet : Completed 304 NOT_MODIFIED
2021-01-23 23:07:22.964 DEBUG 2244 --- [p-nio-80-exec-1] o.s.web.servlet.DispatcherServlet : GET "/invoice", parameters={}
2021-01-23 23:07:22.964 DEBUG 2244 --- [p-nio-80-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to com.my.company.invoise.invoice.api.InvoiceResource#list()
You just called list method
Hibernate:
select
invoice0_.invoice_number as invoice_1_0_,
invoice0_.id_customer as id_custo2_0_,
invoice0_.order_number as order_nu3_0_
from
invoice invoice0_
2021-01-23 23:07:22.980 DEBUG 2244 --- [p-nio-80-exec-1] o.s.w.r.f.client.ExchangeFunctions : [1150dd84] HTTP GET http://MSI:8090/customer/1
2021-01-23 23:07:22.980 DEBUG 2244 --- [p-nio-80-exec-1] o.s.w.c.request.async.WebAsyncManager : Started async request
2021-01-23 23:07:22.980 DEBUG 2244 --- [p-nio-80-exec-1] o.s.web.servlet.DispatcherServlet : Exiting but response remains open for further handling
2021-01-23 23:07:28.012 DEBUG 2244 --- [oundedElastic-2] o.s.w.c.request.async.WebAsyncManager : Async error, dispatch to /invoice
2021-01-23 23:07:28.012 DEBUG 2244 --- [p-nio-80-exec-2] o.s.web.servlet.DispatcherServlet : "ASYNC" dispatch for GET "/invoice", parameters={}
2021-01-23 23:07:28.012 DEBUG 2244 --- [p-nio-80-exec-2] s.w.s.m.m.a.RequestMappingHandlerAdapter : Resume with async result [org.springframework.web.reactive.function.client.WebClientRequestException: failed to resolve 'MSI' (truncated)...]
2021-01-23 23:07:28.012 DEBUG 2244 --- [p-nio-80-exec-2] o.s.web.servlet.DispatcherServlet : Unresolved failure from "ASYNC" dispatch: org.springframework.web.reactive.function.client.WebClientRequestException: failed to resolve 'MSI' after 2 queries ; nested exception is java.net.UnknownHostException: failed to resol