首頁 > Java > java教程 > 詳細講解springcloud的組件之RestTemplate整合的Ribbbon

詳細講解springcloud的組件之RestTemplate整合的Ribbbon

php是最好的语言
發布: 2018-08-02 14:28:02
原創
2840 人瀏覽過

本文講的是springcloud是如何整合ribbon的,不同的springcloud的元件(feign,zuul,RestTemplate)整合ribbon有所不同,這篇文章先來看看RestTemplate。

RestTemplate的類別圖如下

詳細講解springcloud的組件之RestTemplate整合的Ribbbon

  • #HttpAccessor主要根據ClientHttpRequestFactory建立ClientHttpRequest

  • InterceptingHttpAccessor擴充了HttpAccessor,建立攔截的InterceptingClientHttpRequest,這裡會設定攔截器ClientHttpRequestInterceptor,這是整合ribbon的核心,當RestTemplate發起http請求呼叫的時候,會先經過攔截器,然後才真正發起http請求。

攔截器ClientHttpRequestInterceptor是如何被設定的呢?在LoadBalancerAutoConfiguration類別中,有以下程式碼:

@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
登入後複製

只要加入註解@LoadBalancedRestTemplate會被注入,在沒有引入spring retry元件的時候,載入如下配置:

@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);
            }
        };
    }
}
登入後複製

這樣RestTemplate就被設定了LoadBalancerInterceptor,下面來看看整個呼叫過程

詳細講解springcloud的組件之RestTemplate整合的Ribbbon

整個過程有點複雜,核心就是經過攔截器LoadBalancerInterceptor,透過RibbonLoadBalancerClient發起負載平衡呼叫。 RibbonLoadBalancerClientI組合了LoadBalancer,所以具備了負載平衡的能力,也就是我們在上一篇文章解讀的ribbon原理。

圖中我們沒有畫出真正發起http請求的過程,其預設是由SimpleClientHttpRequestFactory創建,ClientHttpRequestFactory的類別圖如下:

詳細講解springcloud的組件之RestTemplate整合的Ribbbon

#從呼叫時序圖上我們看到,開始我們呼叫的是InterceptingClientHttpRequestFactory來取得InterceptingClientHttpRequest,它們透過組合的方式整合了ClientHttpRequestFactory和攔截器,InterceptingClientHttpRequest發起呼叫的時候委託了其內部類別InterceptingRequestExecution去處理,核心邏輯:

@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<String, List<String>> entry : request.getHeaders().entrySet()) {
            List<String> values = entry.getValue();
            for (String value : values) {
                delegate.getHeaders().add(entry.getKey(), value);
            }
        }
        if (body.length > 0) {
            StreamUtils.copy(body, delegate.getBody());
        }
        return delegate.execute();
    }
}
登入後複製

首先會先取出攔截器集合的第一個執行,當攔截器執行完成後,會回調回來,執行else的程式碼,真正發起http請求,主要有兩種方式實作ClientHttpRequestFactory介面:

  • 一種是SimpleClientHttpRequestFactory,使用J2SE提供的方式(既java.net套件提供的方式)建立底層的Http請求連線

  • 一種方式是使用HttpComponentsClientHttpRequestFactory方式,底層使用HttpClient存取遠端的Http服務,使用HttpClient可以設定連線池和憑證等資訊。

 RestTemplate預設是使用SimpleClientHttpRequestFactory,內部是呼叫jdk的HttpConnection,預設逾時為-1,可以這樣設定逾時時間:

@Bean
@LoadBalanced
public RestTemplate restTemplate() {
    SimpleClientHttpRequestFactory factory  = new SimpleClientHttpRequestFactory();
    factory.setConnectTimeout(1000 * 2);//连接超时时间
    factory.setReadTimeout(1000 * 1);//读超时时间
    return new RestTemplate(factory);
}
登入後複製

使用HttpComponentsClientHttpRequestFactory#HttpRequestFactory#HttpComponentsClientHttpRequestFactory方式可以使用連線池(推薦) ,還可以設定重試策略(具體沒有研究過)

如果想開啟重試機制,我們可以引入spring的retry元件

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
    <version>版本号</version>
</dependency>
登入後複製

這樣springcloud-ribbon就會加重如下配置:

@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);
}
登入後複製

攔截器替換成RetryLoadBalancerInterceptor了,這裡整合了retry元件retryTemplate。重試策略由RetryHandler介面來配置,預設實作類別DefaultLoadBalancerRetryHandler,如下為預設的設定參數

#最大的重试次数
ribbon.MaxAutoRetries=0
#最大重试server的个数
ribbon.MaxAutoRetriesNextServer=1
#是否开启任何异常都重试(默认在get请求下会重试,其他情况不会重试,除非设置为true)
ribbon.OkToRetryOnAllOperations=false
#指定重试的http状态码
ribbon.retryableStatusCodes=500,501
登入後複製

以上是對全域生效,如果加上xxx.ribbon.MaxAutoRetries=1這樣只會對某個ribbon客戶端生效。 MaxAutoRetries和MaxAutoRetriesNextServer是搭配使用的,最大重試次數是針對每一個server的,如果設定MaxAutoRetries=1,MaxAutoRetriesNextServer=1這樣觸發最大重試次數就是4次。

相關文章:

Java 實例 - 陣列轉集合

以上是詳細講解springcloud的組件之RestTemplate整合的Ribbbon的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板