ホームページ  >  記事  >  Java  >  springcloudコンポーネントのRestTemplateで統合されたリボンの詳細説明

springcloudコンポーネントのRestTemplateで統合されたリボンの詳細説明

php是最好的语言
php是最好的语言オリジナル
2018-08-02 14:28:022797ブラウズ

この記事では、springcloud がリボンをどのように統合するかについて説明します。さまざまな springcloud コンポーネント (feign、zuul、RestTemplate) が異なる方法でリボンを統合します。この記事では、まず RestTemplate について説明します。

RestTemplateのクラス図は以下の通りです

springcloudコンポーネントのRestTemplateで統合されたリボンの詳細説明

  • HttpAccessorは主にClientHttpRequestを作成します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で統合されたリボンの詳細説明

整个过程有点复杂,核心就是经过拦截器LoadBalancerInterceptor,通过RibbonLoadBalancerClient发起负载均衡调用。RibbonLoadBalancerClientI组合了LoadBalancer,所以具备了负载均衡的能力,也就是我们在上一篇文章解读的ribbon原理。

图中我们没有画出真正发起http请求的过程,其默认是由SimpleClientHttpRequestFactory创建,ClientHttpRequestFactory的类图如下:

springcloudコンポーネントのRestTemplateで統合されたリボンの詳細説明

从调用时序图上我们看到,开始我们调用的是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方式可以使用连接池(推荐) ,还可以设置重试策略(具体没有研究过)

如果想开启重试机制,我们可以引入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

InterceptingHttpAccessor HttpAccessor を拡張して、インターセプトされた InterceptingClientHttpRequest を作成します。ここで、インターセプター ClientHttpRequestInterceptor が設定されます。これは、統合リボン When RestTemplate は http リクエストの呼び出しを開始します。最初にインターセプターを通過し、次に実際に http リクエストを開始します。

インターセプター ClientHttpRequestInterceptor はどのように設定されますか? LoadBalancerAutoConfiguration クラスには、次のコードがあります:

rrreee 注釈 @LoadBalanced が追加されている限り、RestTemplate が挿入されます。 Spring Retry コンポーネントを導入せずに、次の設定をロードします: rrreee

このようにして、RestTemplate が LoadBalancerInterceptor に設定されます🎜🎜springcloudコンポーネントのRestTemplateで統合されたリボンの詳細説明🎜🎜プロセス全体は少し複雑です中心となるのは、インターセプター LoadBalancerInterceptor を通過し、RibbonLoadBalancerClient を通じて負荷分散呼び出しを開始することです。 ibbonLoadBalancerClientI は LoadBalancer を組み合わせているため、負荷分散機能が備わっています。これは、前の記事で説明したリボンの原理です。 🎜🎜図では実際に http リクエストを開始するプロセスは描いていません。デフォルトは SimpleClientHttpRequestFactory によって作成されます。ClientHttpRequestFactory のクラス図は次のとおりです。  springcloudコンポーネントのRestTemplateで統合されたリボンの詳細説明 🎜🎜呼び出しシーケンス図から、最初に InterceptingClientHttpRequestFactory を呼び出して、 を統合した <code>InterceptingClientHttpRequest を取得したことがわかります。 ClientHttpRequestFactory は とインターセプターの組み合わせにより、 InterceptingClientHttpRequest が呼び出しを開始すると、その内部クラス InterceptingRequestExecution に処理を委託します。 🎜rrreee🎜 は最初に実行します。インターセプター コレクションの出力 最初の実行では、インターセプターが完了するとコールバックし、else コードが実行され、実際に http リクエストが開始されます。 ClientHttpRequestFactory インターフェイスを実装するには、主に 2 つの方法があります。 🎜🎜 1 つは SimpleClientHttpRequestFactory です。J2SE によって提供されるメソッド (java.net パッケージによって提供されるメソッド) を使用して、基礎となる Http リクエスト接続を作成します🎜🎜🎜 1 つの方法は、 HttpComponentsClientHttpRequestFactory メソッドでは、最下層は HttpClient を使用してリモート Http サービスにアクセスし、接続プール、証明書、その他の情報を構成できます。 🎜🎜 RestTemplate はデフォルトで SimpleClientHttpRequestFactory を使用し、デフォルトのタイムアウトは -1 です。 🎜rrreee🎜 HttpComponentsClientHttpRequestFactoryを使用します。 > メソッド. 接続プール (推奨)、再試行戦略を設定することもできます (具体的には検討していません) 🎜🎜再試行メカニズムを有効にしたい場合は、Spring の再試行コンポーネントを導入できます🎜rrreee🎜 このように、springcloud-ribbon は追加します。次の構成:🎜rrreeerrreee🎜 インターセプターは RetryLoadBalancerInterceptor に置き換えられ、再試行コンポーネント retryTemplate が統合されています。再試行戦略は、RetryHandler インターフェースによって構成されます。デフォルトの実装クラスは、DefaultLoadBalancerRetryHandler です。上記は、 の場合にグローバルに有効です。 >xxx が追加されました .ribbon.MaxAutoRetries=1これは、特定のリボン クライアントでのみ有効になります。 MaxAutoRetries と MaxAutoRetriesNextServer を併用すると、各サーバーの最大再試行回数が MaxAutoRetries=1 および MaxAutoRetriesNextServer=1 に設定されている場合、トリガーされる最大再試行回数は 4 回になります。 🎜🎜関連記事: 🎜🎜🎜🎜Java の例 - 配列からコレクションへ🎜🎜

以上がspringcloudコンポーネントのRestTemplateで統合されたリボンの詳細説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。