Home  >  Article  >  Java  >  Detailed explanation of the Ribbon integrated by RestTemplate of springcloud components

Detailed explanation of the Ribbon integrated by RestTemplate of springcloud components

php是最好的语言
php是最好的语言Original
2018-08-02 14:28:022723browse

This article talks about how springcloud integrates ribbon. Different springcloud components (feign, zuul, RestTemplate) integrate ribbon differently. This article first takes a look at RestTemplate.

The class diagram of RestTemplate is as follows

Detailed explanation of the Ribbon integrated by RestTemplate of springcloud components

  • ##HttpAccessor is mainly created based on ClientHttpRequestFactory ##ClientHttpRequest

  • ##InterceptingHttpAccessor
  • extends

    HttpAccessor to create an intercepted InterceptingClientHttpRequest, where the interception will be set Device ClientHttpRequestInterceptor, which is the core of the integrated ribbon. When RestTemplate initiates an http request call, it will first go through the interceptor and then actually initiate the http request.

    Interceptor
  • ClientHttpRequestInterceptor
How is it set up? In the

LoadBalancerAutoConfiguration class, there is the following code:

@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
As long as the annotation @LoadBalanced

is added, the

RestTemplate will be injected. If spring retry is not introduced, When loading the component, load the following configuration:

@Configuration
@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
static class LoadBalancerInterceptorConfig {
    @Bean
    public LoadBalancerInterceptor ribbonInterceptor(
        LoadBalancerClient loadBalancerClient,
        LoadBalancerRequestFactory requestFactory) {
        return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
    }

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

is set to LoadBalancerInterceptor. Let’s take a look at the entire calling process

The whole process is a bit complicated. The core is to initiate a load balancing call through the interceptor LoadBalancerInterceptor and RibbonLoadBalancerClient. RibbonLoadBalancerClientI combines LoadBalancer, so it has the ability to load balance, which is the ribbon principle we explained in the previous article. Detailed explanation of the Ribbon integrated by RestTemplate of springcloud components

We did not draw the actual process of initiating an http request in the figure. The default is created by

SimpleClientHttpRequestFactory

. The class diagram of

ClientHttpRequestFactory is as follows:

##We can see from the calling sequence diagram that at first we called Detailed explanation of the Ribbon integrated by RestTemplate of springcloud componentsInterceptingClientHttpRequestFactory to obtain

InterceptingClientHttpRequest

, which are combined The method integrates ClientHttpRequestFactory and the interceptor. When InterceptingClientHttpRequest initiates the call, it delegates its internal class InterceptingRequestExecution to handle it. The core logic is: <pre class="brush:js;toolbar:false;">@Override public ClientHttpResponse execute(HttpRequest request, byte[] body) throws IOException { if (this.iterator.hasNext()) { ClientHttpRequestInterceptor nextInterceptor = this.iterator.next(); return nextInterceptor.intercept(request, body, this); }else { ClientHttpRequest delegate = requestFactory.createRequest(request.getURI(), request.getMethod()); for (Map.Entry&lt;String, List&lt;String&gt;&gt; entry : request.getHeaders().entrySet()) { List&lt;String&gt; values = entry.getValue(); for (String value : values) { delegate.getHeaders().add(entry.getKey(), value); } } if (body.length &gt; 0) { StreamUtils.copy(body, delegate.getBody()); } return delegate.execute(); } }</pre> First, the first execution of the interceptor collection will be taken out. When the execution of the interceptor is completed, it will be called back, execute the else code, and actually initiate the http request. There are two main ways to implement the ClientHttpRequestFactory interface:

One is

SimpleClientHttpRequestFactory
    , which uses the method provided by J2SE (the method provided by the java.net package) to create the underlying Http request connection
  • One way is to use the

    HttpComponentsClientHttpRequestFactory
  • method. The bottom layer uses HttpClient to access the remote Http service. You can use HttpClient to configure the connection pool, certificate and other information.
  • RestTemplate defaults to using SimpleClientHttpRequestFactory, which internally calls HttpConnection of jdk. The default timeout is -1. You can set the timeout like this:

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        SimpleClientHttpRequestFactory factory  = new SimpleClientHttpRequestFactory();
        factory.setConnectTimeout(1000 * 2);//连接超时时间
        factory.setReadTimeout(1000 * 1);//读超时时间
        return new RestTemplate(factory);
    }
  • Use
HttpComponentsClientHttpRequestFactory

You can use a connection pool (recommended), and you can also set a retry strategy (not studied specifically)

If you want to enable the retry mechanism, we can introduce spring's retry component<pre class="brush:js;toolbar:false;">&lt;dependency&gt; &lt;groupId&gt;org.springframework.retry&lt;/groupId&gt; &lt;artifactId&gt;spring-retry&lt;/artifactId&gt; &lt;version&gt;版本号&lt;/version&gt; &lt;/dependency&gt;</pre> In this way, springcloud-ribbon will add the following configuration:

@Configuration
@ConditionalOnClass(RetryTemplate.class)
public static class RetryAutoConfiguration {
    @Bean
    public RetryTemplate retryTemplate() {
        RetryTemplate template =  new RetryTemplate();
        template.setThrowLastExceptionOnExhausted(true);
        return template;
    }

    @Bean
    @ConditionalOnMissingBean
    public LoadBalancedRetryPolicyFactory loadBalancedRetryPolicyFactory() {
        return new LoadBalancedRetryPolicyFactory.NeverRetryFactory();
    }
}

@Configuration
@ConditionalOnClass(RetryTemplate.class)
public static class RetryInterceptorAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean
    public RetryLoadBalancerInterceptor ribbonInterceptor(
        LoadBalancerClient loadBalancerClient, LoadBalancerRetryProperties properties,
        LoadBalancedRetryPolicyFactory lbRetryPolicyFactory,
        LoadBalancerRequestFactory requestFactory) {
        return new RetryLoadBalancerInterceptor(loadBalancerClient, properties,
                                                lbRetryPolicyFactory, requestFactory);
    }

    @Bean
    @ConditionalOnMissingBean
    public RestTemplateCustomizer restTemplateCustomizer(
        final RetryLoadBalancerInterceptor loadBalancerInterceptor) {
        return new RestTemplateCustomizer() {
            @Override
            public void customize(RestTemplate restTemplate) {
                List<ClientHttpRequestInterceptor> list = new ArrayList<>(
                    restTemplate.getInterceptors());
                list.add(loadBalancerInterceptor);
                restTemplate.setInterceptors(list);
            }
        };
    }
}
@Bean
@ConditionalOnClass(name = "org.springframework.retry.support.RetryTemplate")
@ConditionalOnMissingBean
    public LoadBalancedRetryPolicyFactory loadBalancedRetryPolicyFactory(SpringClientFactory clientFactory) {
    return new RibbonLoadBalancedRetryPolicyFactory(clientFactory);
}

The interceptor is replaced with

RetryLoadBalancerInterceptor

, where the retry component retryTemplate is integrated. The retry strategy is configured by the

RetryHandler

interface. The default implementation class is DefaultLoadBalancerRetryHandler. The following are the default configuration parameters <pre class="brush:js;toolbar:false;">#最大的重试次数 ribbon.MaxAutoRetries=0 #最大重试server的个数 ribbon.MaxAutoRetriesNextServer=1 #是否开启任何异常都重试(默认在get请求下会重试,其他情况不会重试,除非设置为true) ribbon.OkToRetryOnAllOperations=false #指定重试的http状态码 ribbon.retryableStatusCodes=500,501</pre>. The above is globally effective. If ## is added #xxx.ribbon.MaxAutoRetries=1This will only take effect on a certain ribbon client. MaxAutoRetries and MaxAutoRetriesNextServer are used together. The maximum number of retries is for each server. If MaxAutoRetries=1 and MaxAutoRetriesNextServer=1 are set, the maximum number of retries triggered is 4 times.

Related articles:

Java Example - Array to Collection


The above is the detailed content of Detailed explanation of the Ribbon integrated by RestTemplate of springcloud components. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn