资讯专栏INFORMATION COLUMN

RestTemplate集成Ribbbon

wall2flower / 3141人阅读

摘要:的类图如下主要根据创建扩展了,创建拦截的,这里会设置拦截器,这是集成的核心,当发起请求调用的时候,会先经过拦截器,然后才真正发起请求。和是配合使用的,最大重试次数是针对每一个的,如果设置,这样触发最大重试次数就是次。

上一篇文章我们分析了ribbon的核心原理,接下来我们来看看springcloud是如何集成ribbon的,不同的springcloud的组件(feign,zuul,RestTemplate)集成ribbon有所不同,这篇文章先来看看RestTemplate。

RestTemplate的类图如下

HttpAccessor主要根据ClientHttpRequestFactory创建ClientHttpRequest

InterceptingHttpAccessor扩展了HttpAccessor,创建拦截的InterceptingClientHttpRequest,这里会设置拦截器ClientHttpRequestInterceptor,这是集成ribbon的核心,当RestTemplate发起http请求调用的时候,会先经过拦截器,然后才真正发起http请求。

拦截器ClientHttpRequestInterceptor是如何被设置的呢?在LoadBalancerAutoConfiguration类中,有如下代码:

@LoadBalanced
@Autowired(required = false)
private List 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 list = new ArrayList<>(
                    restTemplate.getInterceptors());
                list.add(loadBalancerInterceptor);
                restTemplate.setInterceptors(list);
            }
        };
    }
}

这样RestTemplate就被设置了LoadBalancerInterceptor,下面来看看整个调用过程

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

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

从调用时序图上我们看到,开始我们调用的是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> entry : request.getHeaders().entrySet()) {
            List 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组件


    org.springframework.retry
    spring-retry
    版本号

这样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 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次。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/76592.html

相关文章

  • SpringCloud(第 014 篇)电影 Ribbon 微服务集成 Hystrix 断路器实现失

    摘要:当服务宕机或者不可用时,即请求超时后会调用此方法。添加电影微服务启动类电影微服务集成断路器实现失败快速响应,达到熔断效果。 SpringCloud(第 014 篇)电影 Ribbon 微服务集成 Hystrix 断路器实现失败快速响应,达到熔断效果 - 一、大致介绍 1、Hystrix 断路器的原理很简单,如同电力过载保护器。它可以实现快速失败,如果它在一段时间内侦测到许多类似的错误,...

    StonePanda 评论0 收藏0
  • SpringCloud(第 015 篇)电影Ribbon微服务集成Hystrix增加隔离策略控制指标

    摘要:传播安全上下文或使用,通过增加的属性,来增加相关的配置来达到执行隔离策略,控制线程数或者控制并发请求数来达到熔断降级的作用。 SpringCloud(第 015 篇)电影Ribbon微服务集成Hystrix增加隔离策略控制线程数或请求数来达到熔断降级的作用 - 一、大致介绍 1、本章节介绍关于Hystrix的2种隔离方式(Thread Pool 和 Semaphores); 2、Thr...

    RobinQu 评论0 收藏0
  • Spring Cloud中如何优雅的使用Feign调用接口

    摘要:对进行了封装,使其支持标准注解和。可以与和组合使用以支持负载均衡。中使用当我们搭建好注册中心之后,就是需要将自己的服务注册到中,然后别的服务可以直接调用。 JAVA 项目中接口调用怎么做 ? Httpclient Okhttp Httpurlconnection RestTemplate 上面是最常见的几种用法,我们今天要介绍的用法比上面的更简单,方便,它就是 Feign Feig...

    ChanceWong 评论0 收藏0
  • Spring新功能

    摘要:新特性重要功能升级为了解决各种环境下如开发测试和生产选择不同配置的问题,引入了环境功能。这个消息模块支持的功能,同时提供了基于模板的方式发布消息是第一批支持特性的框架,比如它所支持的表达式。 Spring 3.1新特性 重要功能升级 为了解决各种环境下(如开发、测试和生产)选择不同配置的问题,Spring 3.1引入了环境profile功能。借助于profile,就能根据应用部署在什...

    baiy 评论0 收藏0
  • SpringCloud学习(2)

    摘要:此为的结构图上篇已注册了,的服务,接下来用,实现负载均衡和的简单客户端,让消费者调用服务。是发布的云中间层服务开源项目,其主要功能是提供客户侧软件负载均衡算法,将的中间层服务连接在一起。对选定的负载均衡策略机上重试机制。           上篇已经搭建好基础demo,接下来继续构建项目并对spring cloud组件介绍描述。 showImg(https://segmentfault...

    wenzi 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<