This is the 19th day of my participation in the Gwen Challenge in November. Check out the details: The last Gwen Challenge in 2021

This series code address: github.com/JoJoTec/spr…

Why encapsulate the asynchronous HTTP client WebClient

For synchronous requests, we use the Spring-Cloud-OpenFeign wrapped FeignClient with additional customization. For asynchronous requests, an asynchronous Http client, the WebClient, is used. WebClient is also relatively easy to use. A simple example is:

WebClient = webclient.builder () // specify the base address. BaseUrl ("http://httpbin.org") // You can specify some default parameters, such as default Cookie, DefaultCookie ("cookieKey", "cookieValue"). DefaultHeader (HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .build();Copy the code

After the WebClient is created, you can use the WebClient to call:

// GET request /anything and convert body to String Mono<String> stringMono = client.get().uri("/anything").retrieve().bodyToMono(String.class); Block = stringmono.block ();Copy the code

The result is as follows (httporg. Bin /anything will return everything in the request intact, as we can see from this Header and cokkie are returned) :

{ "args": {}, "data": "", "files": {}, "form": {}, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip", "Cookie": "TestCookie=TestCookieValue,getAnythingCookie=getAnythingCookieValue", "Getanythingheader": "getAnythingHeaderValue", "Host": "httpbin.org", "Testheader": "TestHeaderValue", "User-Agent": "ReactorNetty / 1.0.7"}, "json", null, "method" : "GET", "origin" : "12.12.12.12", "url" : "http://httpbin.org/anything"}Copy the code

We can also add load balancing function, let WebClient use our internal LoadBalancer, load balancing to call other microservices, first inject load balancing Filter:

@Autowired
ReactorLoadBalancerExchangeFilterFunction lbFunction;
Copy the code

When creating WebClient, add this Filter:

WebClient = webclient.builder () // specify the base microservice.baseurl (" http://microservice name ") // You can specify some default parameters, such as default Cookie, DefaultCookie ("cookieKey", "cookieValue"). DefaultHeader (HttpHeaders.CONTENT_TYPE, APPLICATION_JSON_VALUE) // Load balancer, rewrite url.filter (lbFunction).build();Copy the code

This way, the WebClient can call the microservice.

However, this is not enough for our needs:

  1. We need to add retry and break mechanism like Feignclient in WebClient, thread isolation is not needed, because all asynchronous requests do not block the task thread.
  2. Different connection and response timeouts need to be configured for different microservices to accommodate different microservices.
  3. These configurations increase the complexity of the code, and we need to reduce the intrusion of the code to the business. It is best to implement the WebClient initialization through pure configuration.

Configuration design and usage examples to be implemented

First, we will implement WebClient, whose Filter contains three:

  1. Retry Filter: The retry Filter must be before the load balancer Filter. During retry, the load balancer obtains another instance from the load balancer and tries again, rather than retry multiple times on the same instance.
  2. Load Balancing FilterIt’s actually built inReactorLoadBalancerExchangeFilterFunction
  3. Circuit breaker Filter: Circuit breakers need to be after load balancing, because only after load balancing can we get the specific locally called service instances, so we can implement circuit breakers based on microservice instance method level.

Retry scenarios:

  1. A non-2XX response code is returned, and the method is a retried method. How to define a method to be retried, first the GET method is retried, and for other methods, it can be retried depending on whether the URL is configured in the configuration.
  2. Abnormal retry:
    1. Connection exception: such as connection timeout, broken connection, etc. All requested connection exceptions can be retried because the request was not sent.
    2. Breaker exception: The service instance method level breaker is open and the other instances need to be retried directly because the request was not sent.
    3. Response timeout exception: This retry logic returns the same as a non-2XX response code.

The configuration we need to implement is by configuring application.yml like this:

Webclient: configs: // Microservice name testService1: // Request base address, first level domain name as microservice name baseUrl: http://testService1 // maximum number of HTTP connections maxConnection: 50 // connection timeout connectTimeout: 500ms // responseTimeout responseTimeout: 60s // Which paths can retry retryablePaths besides GET: - /retryable/** - /user/ordersCopy the code

By adding these configurations, we can get the Bean that holds the corresponding WebClient for the microservice, for example:

// Automatically load our custom WebClient NamedContextFactory, This is behind us in order to realize @autowired private WebClientNamedContextFactory WebClientNamedContextFactory; / / by micro service name, obtain the corresponding micro service invocation WebClient webClientNamedContextFactory. GetWebClient (" testService1 ");Copy the code

And then we’re going to implement that.

Wechat search “my programming meow” public account, a daily brush, easy to improve skills, won a variety of offers