Ribbon Spring provides a simple and convenient template class for API calls. It is called RestTemplate.

Fsh-house: HouseController {fsh-house: HouseController {fsh-house: HouseController {fsh-house: HouseController {fsh-house: HouseController {fsh-house: HouseController {fsh-house: HouseController {fsh-house: HouseController}} The other passes arguments via @pathvarable, returning a string. Try to assemble different forms from both interfaces, as shown in the code below. @GetMapping(“/data”)public HouseInfo getData( @RequestParam(“name”) String name) {

Return new HouseInfo(1L, “Shanghai”, “Hongkou”, “Dongti District “); } @GetMapping(“/data/{name}”) public String getData2(@PathVariable( “name”) String name) {

return name; } Use the RestTemplate in the FSH-Substitution service to invoke the two interfaces we just defined, as shown in the code below.

@GetMapping(“/data”) public HouseInfo getData(@RequestParam(“name”) String name) {

return restTemplate.getForobject( “); }

@GetMapping(“/data/{name}”) public String getData2(@PathVariable(“name”) String name) { return restTemplate.getForobject(

“{name}”,String.class,name); } Get the result of the data via the getForObject method of RestTemplate (as shown in the code below), which has three overloaded implementations:

Url: Request API address, there are two ways, one is a string, the other is a URL. ResponseType: The type of the return value. UriVariables: PathVariable parameters, there are two ways, one is a variable parameter, the other is a Map form. public T getForobject(String url, Class responseType,

object… uriVariables); public T getForobject (String url, Class responseType ,

Map<String, ? > uriVariables) ; public T getForobject(URI url, Class responseType) ; In addition to getForObject, we can also use getForEntity to get data, as shown in the code below.

@GetMapping(” /data”)public HouseInfo getData(@RequestParam(“name”) String name) {

ResponseEntity responseEntity = restTemplate.getForEntity( “http:/ /localhost: 8081 /house/ data? name= “+name, HouseInfo.class) ; if (responseEntity.getStatusCodeValue() == 200) { return responseEntity.getBody(); } return nu1l ; } getForEntity can obtain the returned status code, request information, etc., and get the content of the response through getBody. The rest, like getForObject, have three overloaded implementations.

Let’s see how to call the interface using POST. Add a save method in HouseController to receive HouseInfo data, as shown in the code below.

@PostMapping(“/save”)public Long addData(@RequestBody HouseInfo houseInfo) {

System.out.println(houseInfo. getName()); return 1001L; } Then write the call code, using postForObject, as shown below.

@GetMapping(“/save”)public Long add(){

HouseInfo houseInfo = new HouseInfo(); HouseInfo. SetCity (” Shanghai “); HouseInfo. SetRegion (” hongkou “); houseInfo.setName( “XXX”); Long id = restTemplate.postFor0bject( “http: //1ocalhost:8081/ house/save”,houseInfo,Long.class); return id; } postForObject also has three overloaded implementations. In addition to postForObject, you can also use postForEntity, which is the same, as shown in the code below.

public T postForobject(String url, object request,

Class responseType, object… uriVariables); public T postForobject(String url, object request,

Class responseType, Map<String, ? > urivariables); public T postForobject(URI url, object request, Class responseType); In addition to the get and POST methods, RestTemplate provides put, DELETE, and more useful exchange methods. Exchange can perform get, POST, PUT, and DELETE requests.

Integrating the Ribbon To integrate the Ribbon in a Spring Cloud project requires only the following dependencies in pom.xml, which you don’t need to configure because Eureka already references the Ribbon, as shown in the code below.

Org. Springframework. Cloud spring – the cloud – starter – ribbon this configuration we add in fangjia – FSH – substitution – service.

The RestTemplate load balancing example does a little tweaking of the previous code and outputs something to prove that our integrated Ribbon works.

Modify the Hello interface to output the port of the current service in the interface to distinguish the called service, as shown in the code below.

@RestController@RequestMapping(“/house” )public class HouseController {

@Value(“${server .port}”) private String serverPort;

@GetMapping(“/hel1o”) public String hel1o(){ return “Hello”+serverPort; }} The above code starts two services with ports 8081 and 8083, respectively, which will be used later.

Then modify the code for the callHello interface to output the call results to the console, as shown in the code below.

@RestController@RequestMapping(“/substitution”)public class Substitut ionController{

@Autowired private RestTemplate restTemplate; @GetMapping (“/cal1Hel1o”) public String cal1Hello(){ String result = restTemplate. getFor0bject( “); System.out.print1n(” call result: “+ result); return result ; }} Test steps are as follows:

Restart the service. Access interface. Look at the console output to see if the load is working.

I believe you must have a question: Why is it that by adding @loadbalanced to RestTemplate, the RestTemplate can be integrated with Eureka, can call interfaces using service names, and can be LoadBalanced?

The credit goes to Spring Cloud for doing a lot of low-level work for us, because it encapsulates it and makes it easy to use. Frameworks are created to simplify code and improve efficiency.

The main logic is to add an interceptor to the RestTemplate, either to replace the requested address before it is requested, or to select the service address based on a specific load policy and then call it, which is how @loadBalanced works.

Let’s implement a simple interceptor and see if we can enter it before calling the interface. We don’t have to do anything, just print out a sentence to prove that we can get in. As shown in the code below.

public class MyLoadBalancerInterceptor implements ClientHttpRequestInterceptor{

@Override public ClientHttpResponse intercept (final HttpRequest request , final byte[] body, final ClientHttpRequestExecution execution) throws IOException{ final URI originalUri = request.getURI(); String serviceName = originalUri.getHost(); System.out.println(” enter custom request interceptor “+serviceName); return execution.execute(request, body); }} once the interceptor is ready, we’ll define an annotation, copy the @loadBalanced code, and rename it, as shown below.

@Target({ ElementType.FIELD,ElementType.PARAMETER,ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Documented Then define a configuration class to annotate the RestTemplate interceptor, as shown in the code below.

@Configurationpublic class MyLoadBalancerAutoConfiguration{

@MyLoadBalanced @Autowired(required = false) private List restTemplates = Collections.emptyList();

@Bean public MyLoadBalancerInterceptor myLoadBalancerInterceptor() { return new MyLoadBalancerInterceptor(); }

@Bean public SmartInitializingSingleton myLoadBalancedRestTemplateInitializer() { return new SmartInitializingSingleton() { @Override public void afterSingletonsInstantiated() { for (RestTemplate restTemplate : MyLoadBalancerAutoConfiguration.this.restTemplates){ List list = new ArrayList<>(restTemplate.getInterceptors()); list.add(myLoadBalancerInterceptor()); restTemplate.setInterceptors(list); }}}; }} to maintain a @ MyLoadBalanced RestTemplate list, the RestTemplate in SmartlnitializingSingleton blocker Settings.

Then modify our previous RestTemplate configuration to change @LoadBalanced to our custom @MyLoadBalanced, as shown in the code below.

@Bean//@LoadBalanced@MyLoadBalancedpublic RestTemplate getRestTemplate(){

return new RestTemplate() ; } Restart the service and access to the console can see the output, which proves that the interceptor will be entered when the interface is called, the output is as follows:

This small example gives you a good idea of how @LoadBalanced works. Let’s take a look at the logic in the source code.

First look at the configuration class, how to set up interceptors for RestTemplate, The code in the spring — cloud commonsjar orgspringframework. Cloud. Client. Loadbalancer. LoadBalancerAutoConfiguration class by looking at the inside LoadBalancerAutoConfiguration page + source code, you can see here is also maintains a @ LoadBalanced RestTemplate list, as shown in the following code.

@LoadBalanced@Autowired(required = false)private List restTemplates = Collections.emptyList(); @Beanpublic SmartInitializingSingleton loadBalancedRestTemplateInitializer(

final List<RestTemplateCustomizer> customizers) {
Copy the code

return new SmartInitializingSingleton() { @Override public void afterSingletonsInstantiated() { for(RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) { for (RestTemplateCustomizer customizer:customizers) { customizer.customize(restTemplate);

}}}Copy the code

}; } Let’s look at the configuration of the interceptor. As you can see, the interceptor is a LoadBalancerInterceptor, and the RestTemplate Customizer is used to add the interceptor, as shown in the code below.

@Configuration @conditionalOnMissingClass(“org.springframework.retry.support.RetryTemplate”)static class LoadBalancerInterceptorConfig {

@Bean public LoadBalancerInterceptor ribbonInterceptor ( LoadBalancerClient loadBalancerClient , LoadBalancerRequestFactory requestFactory) return new LoadBalancer Interceptor(loadBalancerClient,requestFactory); }

@Bean @ConditionalOnMissingBean public RestTemplateCustomizer restTemplateCustomizer( final LoadBalancerInterceptor loadBalancerInterceptor) { return new RestTemplateCustomizer() { @Override public void customize(RestTemplate restTemplate) { List list = new ArrayList<>( restTemplate.getInterceptors()); list.add(loadBalancer Interceptor); restTemplate. setInterceptors(list); }}; }}

If there is more intuitive understanding of electron, you can also refer to its official website:

www.sangpi.com

public class LoadBalancerInterceptor imp1ements

ClientHttpRequestInterceptor {
Copy the code

private LoadBalancerClient loadBalancer; private LoadBalancerRequestFactory requestFactory; public LoadBalancerInterceptor(LoadBalancerClient loadBalancer , LoadBalancerRequestFactory requestFactory){ this. loadBalancer = loadBalancer; this. requestFactory = requestFactory; } public LoadBalancerInterceptor(LoadBalancerClient loadBalancer) { this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer)); } @Override public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution ) throws IOException { final URI originaluri = request. getURI(); String serviceName = originalUri.getHost(); Assert.state(serviceName ! = nu11, “Request URI does not contain a valid hostname:” + originalUri) ; return this.loadBalancer.execute (serviceName , requestFactory . createRequest(request, body, execution)); }} The main logic in The Intercept is that execution is handled by the LoadBalancerClient, which builds a LoadBalancerRequest object through the LoadBalancer RequestFactory, as shown in the code below.

public LoadBalancerRequest createRequest(final

HttpRequest request, final byte[] body,
    final ClientHttpRequestExecution execution) {
Copy the code

return new LoadBalancerRequest() { @Override public ClientHttpResponse apply(final ServiceInstance instance) throws Exception { HttpRequest serviceRequest = new ServiceRequestwrapper(request, instance, loadBalancer); if (transformers ! = nu11) { for(LoadBalancerRequestTransformer transformer : transformers) { serviceRequest = transformer . transformRequest(serviceRequest, instance); } } return execution. execute ( serviceRequest, body) ; }}; } createRequest performs the URI substitution logic with ServiceRequestWrapper. ServiceRequest Wrapper will URI access to org. Springframework. Cloud. Client. Loadbalancer. Loadbalancer Client# reconstructURI Methods.

This is the implementation process of the entire RestTemplate in combination with @loadBalanced. As for the specific implementation, you can study it yourself. Here is just an introduction to the principle and the whole process.

You can use the LoadBalancer Client to access the fSH-house service through the Ribbon. For example, you can use the LoadBalancer Client to access the FSH-house service. One can be selected using the Choose method of LoadBalancerClient:

@Autowiredprivate LoadBalancerClient loadBalancer; @GetMapping(“/choose”)public object chooseUrl() {

ServiceInstance instance = loadBalancer.choose(“fsh-house”); return instance; } to access the interface, you can see the following information returned:

{

serviceId: “fsh-house”, server: { host: “localhost”, port: 8081, id: “localhost:8081”, zone: “UNKNOWN”, readyToServe: true, alive: true, hostPort: “localhost:8081”, metaInfo: { serverGroup: null, serviceIdForDiscovery: null, instanceId: “localhost:8081”, appName: null } }, secure: false, metadata: { }, host: “localhost”, port: 8081, uri: “} 5, the Ribbon is loaded with a lot of blog posts: When a service is called, if the network condition is bad, the first call will time out. There are plenty of gurus who have come up with solutions to this, such as making the timeout longer, disabling it, etc. Spring Cloud is currently growing at a high speed, with release updates occurring quickly, and most of the problems we can find are fixed or optimally resolved by the time the new version comes out.

The Ribbon initializes the Client at the time of the first request. If the timeout is short, the Client initialization time plus the interface request time will cause the first request to time out.

This problem can be solved by configuring eagle-load to pre-initialize the client.

Enabled = true ribbon eagle-load. Clients = Fsh-house ribbon. Eagle-load. Ribbon. Eagle-load. Clients: Specifies the name of the service that you want to load hungry. If there are more than one, separate them with a comma.