开始
环境
Spring Boot :2.0.8.RELEASE
Spring Cloud : Finchley.SR2
Nacos : 0.8.0
在上一篇中只是大致说了RestTemplate如何实现超时设置,当超时时就会直接抛出异常,在微服务时代各个服务之间互相调用难免因为网络波动导致调用失败的情况,这时候是希望能够实现重试了。
把功能稍微改一下
consume工程修改,把ConnectTimeout与ReadTimeout
public class ConsumeApplication {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
clientHttpRequestFactory.setConnectTimeout(5 * 1000);
clientHttpRequestFactory.setReadTimeout(5 * 1000);
return new RestTemplate(clientHttpRequestFactory);
}
@Autowired
RestTemplate restTemplate;
public static void main(String[] args) {
SpringApplication.run(ConsumeApplication.class, args);
}
@GetMapping("test")
public String getContent(){
log.info("发起请求");
return restTemplate.getForObject("http://provider/provider",String.class);
}
}
provider工程开启运行多实例
先运行一个实例,端口号9667,之后修改端口号为9668,同时修改接口,加个20秒的阻塞
运行如下:
就可以尝试如何实现重试功能了。
RetryTemplate
需要实现重试功能,那么就需要RetryTemplate,在工程中引入
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
在没有引入RetryTemplate之前,Ribbon只负责实现负载均衡,引入之后那么负载均衡就会使用LoadBalancedRetryFactory和RetryLoadBalancerInterceptor,RibbonAutoConfiguration中如下:
@Bean
@ConditionalOnClass(name = "org.springframework.retry.support.RetryTemplate")
@ConditionalOnMissingBean
public LoadBalancedRetryFactory loadBalancedRetryPolicyFactory(final SpringClientFactory clientFactory) {
return new RibbonLoadBalancedRetryFactory(clientFactory);
}
LoadBalancerAutoConfiguration中:
RibbonLoadBalancedRetryFactory中主要负责创建重试策略、重试监听等
public class RibbonLoadBalancedRetryFactory implements LoadBalancedRetryFactory {
private SpringClientFactory clientFactory;
public RibbonLoadBalancedRetryFactory(SpringClientFactory clientFactory) {
this.clientFactory = clientFactory;
}
@Override
public LoadBalancedRetryPolicy createRetryPolicy(String service, ServiceInstanceChooser serviceInstanceChooser) {
RibbonLoadBalancerContext lbContext = this.clientFactory
.getLoadBalancerContext(service);
return new RibbonLoadBalancedRetryPolicy(service, lbContext, serviceInstanceChooser, clientFactory.getClientConfig(service));
}
@Override
public RetryListener[] createRetryListeners(String service) {
return new RetryListener[0];
}
@Override
public BackOffPolicy createBackOffPolicy(String service) {
return null;
}
}
RibbonLoadBalancedRetryPolicy主要用来判断是否能够满足重试条件,主要代码如下
其中canRetry接口用来判断请求类型是否允许重试,默认只允许GET请求能够重试,如果需要所有的请求都能实现重试,那么需要设置OkToRetryOnAllOperations为true(当然不建议这么做)。
canRetryNextServer主要用来判断是否满足调用下一个服务的条件。lbContext.getRetryHandler()是默认的DefaultLoadBalancerRetryHandler,
retrySameServer:默认情况下是0,即重试自身服务的次数为0,
retryNextServer:默认情况下是1,即重试下个服务的次数为1,
retryEnabled:即是否说有请求都重试,默认是false。
自定义设置可以在yml文件中设置:
ribbon:
MaxAutoRetries: 1
MaxAutoRetriesNextServer: 2
到这里发现,Ribbon的ConnectTimeout与ReadTimeout根本没有任何用处,卧槽,是不是很奇怪,哈哈。
在HttpClientRibbonConfiguration中如下:
@Bean
@ConditionalOnMissingBean(CloseableHttpClient.class)
public CloseableHttpClient httpClient(ApacheHttpClientFactory httpClientFactory,
HttpClientConnectionManager connectionManager, IClientConfig config) {
RibbonProperties ribbon = RibbonProperties.from(config);
Boolean followRedirects = ribbon.isFollowRedirects();
Integer connectTimeout = ribbon.connectTimeout();
RequestConfig defaultRequestConfig = RequestConfig.custom()
.setConnectTimeout(connectTimeout)
.setRedirectsEnabled(followRedirects).build();
this.httpClient = httpClientFactory.createBuilder().
setDefaultRequestConfig(defaultRequestConfig).
setConnectionManager(connectionManager).build();
return httpClient;
}
@ConditionalOnMissingBean(CloseableHttpClient.class)即没有实例化CloseableHttpClient的情况下才执行,在上面new HttpComponentsClientHttpRequestFactory 的时候已经创建了CloseableHttpClient,如下:
/**
* Create a new instance of the {@code HttpComponentsClientHttpRequestFactory}
* with a default {@link HttpClient}.
*/
public HttpComponentsClientHttpRequestFactory() {
this.httpClient = HttpClients.createSystem();
}
这里当然就没有用到Ribbon的ConnectTimeout与ReadTimeout了,即使设置也是没得用。
如果想不单独设置HttpComponentsClientHttpRequestFactory,紧密结合Ribbon,那么只要yml文件中设置如下即可
ribbon.http.client.enabled=true或ribbon.restclient.enabled=true都行
这样在RibbonAutoConfiguration中给restTemplate设置RequestFactory