RestTemplate集成Ribbbon的示例代码

网友投稿 281 2023-01-24


RestTemplate集成Ribbbon的示例代码

上一篇文章我们分析了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();

只要加入注解@LoadBalanced的RestTemplate会被注入,在没有引入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 LoadBalancerIhttp://nterceptor loadBalancerInterceptor) {

return new RestTemplateCustomizer() {

@Override

public void customize(RestTemplate restTemplate) {

List list = new ArrayList<>(

restTemplate.getInterceptors());

list.add(loazAeSzwpkdBalancerInterceptor);

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。重试策略由RetryHhttp://andler接口来配置,默认实现类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次。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:网络共享文件系统异常(网络无法显示共享文件)
下一篇:使用maven profile指定配置文件打包适用多环境的方法
相关文章

 发表评论

暂时没有评论,来抢沙发吧~