In the post Spring Boot Microservice - Service Registration and Discovery With Eureka we have seen an example of using Eureka for Service registration and discovery. In that example RestTemplate is used for inter-service communication. In this post we'll see how to use WebClient for communication between microservices.
As per Spring framework documentation:
As of Spring 5.0 org.springframework.web.client.RestTemplate
class is in maintenance mode, with only minor requests
for changes and bugs to be accepted going forward. Please, consider using the org.springframework.web.reactive.client.WebClient
which has a more modern API and supports sync, async, and streaming scenarios.
So, this is one of the reasons for considering using WebClient.
WebClient
Spring WebFlux includes WebClient to call remote REST services. WebClient has a functional, fluent API based on Reactor. It is fully non-blocking and it supports streaming.
Spring Boot Microservice with WebClient example
We'll use the example used in Spring Boot Microservice - Service Registration and Discovery With Eureka as our base example and made changes to it to use WebClient in place of RestTemplate.
Add maven dependency
To use WebClient Spring Webflux is needed so you need to add Webflux starter to your pom.xml. That should be done in CustomerService as this is the service from where we need to communicate with AccountService.
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency>
Configuration for WebClient
We'll configure WebClient.Builder
instance which in turn is used to create a WebClient instance, where ever it is needed
using build() method.
import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.reactive.function.client.WebClient; @Configuration public class WebClientConfig { @Bean @LoadBalanced WebClient.Builder loadBalancedWebClientBuilder(){ return WebClient.builder(); } }
Changes in CustomerService implementation
import java.util.List; import org.springframework.http.MediaType; import org.springframework.stereotype.Service; import org.springframework.web.reactive.function.client.WebClient; import com.netjstech.customerservice.dao.entity.Customer; import com.netjstech.customerservice.dao.repository.CustomerRepository; import com.netjstech.customerservice.dto.AccountDto; import com.netjstech.customerservice.dto.CustomerDto; import com.netjstech.customerservice.exception.CustomerServiceException; import reactor.core.publisher.Flux; @Service public class CustomerServiceWebClientImpl implements CustomerService{ private WebClient.Builder webClientBuilder; private CustomerRepository customerRepository; CustomerServiceWebClientImpl(WebClient.Builder webClientBuilder, CustomerRepository customerRepository){ this.webClientBuilder = webClientBuilder; this.customerRepository = customerRepository; } private String baseURL = "http://ACCOUNT-SERVICE/account/"; @Override public Customer saveCustomer(Customer customer) { return customerRepository.save(customer); } @Override public CustomerDto getCustomerById(Long id) { Customer customer = customerRepository.findById(id) .orElseThrow(()-> new CustomerServiceException("No customer found for the given id - " + id)); Flux<AccountDto> accountFlux = getWebClient(id); System.out.println("Flux " + accountFlux); List<AccountDto> accounts = accountFlux.collectList().block(); System.out.println(accounts); // Need to create CustomerDTO so need accounts data CustomerDto customerDto = CustomerDto.builder() .id(customer.getId()) .name(customer.getName()) .age(customer.getAge()) .city(customer.getCity()) .accounts(accounts) .build(); return customerDto; } Flux<AccountDto> getWebClient(Long customerId){ return webClientBuilder.baseUrl(baseURL) .build() .get() .uri("customer/" + customerId) .accept(MediaType.APPLICATION_JSON) .retrieve() .bodyToFlux(AccountDto.class); } }
For sending request and receiving response there are two methods provided by WebClient- exchange() and retrieve(). Out of
these two, exchange() method is deprecated since Spring 5.3. In place of that there are two alternative methods
exchangeToFlux()
and exchangeToMono()
. These methods provide more control via access to the ClientResponse. This can be
useful for advanced scenarios, for example to decode the response differently depending on the response status.
With retrieve()
method you can declare how to extract the response. For example, you can extract a ResponseEntity
with status, headers, and body or you can just retrieve the body. In the usage as shown above in the CustomerServiceWebClientImpl
only body is retrieved.
After retrieve() method bodyToFlux()
or bodyToMono()
method is used to decode the body to a Flux with elements of the given
type or to decode the body to the given target type. In the example shown here we need a collection of accounts so Flux
is used.
Once these changes are done start the EurekaDiscoveryServiceApplication which starts the Eureka Server. Then start the CustomerService and AccountService applications.
Once all the services are started access http://localhost:8081/customer/1 where internally a call is made to account-service from customer-service using WebClient.
That's all for this topic Spring Boot Microservice Example Using WebClient. If you have any doubt or any suggestions to make please drop a comment. Thanks!
>>>Return to Spring Tutorial Page
Related Topics
You may also like-
No comments:
Post a Comment