本文主要研究一下spring cloud的LoadBalancerAutoConfigurationhtml
spring-cloud-netflix-ribbon-2.0.0.RC2-sources.jar!/org/springframework/cloud/netflix/ribbon/RibbonAutoConfiguration.javajava
@Configuration @ConditionalOnClass(RestTemplate.class) @ConditionalOnBean(LoadBalancerClient.class) @EnableConfigurationProperties(LoadBalancerRetryProperties.class) public class LoadBalancerAutoConfiguration { @LoadBalanced @Autowired(required = false) private List<RestTemplate> restTemplates = Collections.emptyList(); @Bean public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated( final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) { return () -> restTemplateCustomizers.ifAvailable(customizers -> { for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) { for (RestTemplateCustomizer customizer : customizers) { customizer.customize(restTemplate); } } }); } @Autowired(required = false) private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList(); @Bean @ConditionalOnMissingBean public LoadBalancerRequestFactory loadBalancerRequestFactory( LoadBalancerClient loadBalancerClient) { return new LoadBalancerRequestFactory(loadBalancerClient, transformers); } @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 restTemplate -> { List<ClientHttpRequestInterceptor> list = new ArrayList<>( restTemplate.getInterceptors()); list.add(loadBalancerInterceptor); restTemplate.setInterceptors(list); }; } } @Configuration @ConditionalOnClass(RetryTemplate.class) public static class RetryAutoConfiguration { @Bean @ConditionalOnMissingBean public LoadBalancedRetryFactory loadBalancedRetryFactory() { return new LoadBalancedRetryFactory() {}; } } @Configuration @ConditionalOnClass(RetryTemplate.class) public static class RetryInterceptorAutoConfiguration { @Bean @ConditionalOnMissingBean public RetryLoadBalancerInterceptor ribbonInterceptor( LoadBalancerClient loadBalancerClient, LoadBalancerRetryProperties properties, LoadBalancerRequestFactory requestFactory, LoadBalancedRetryFactory loadBalancedRetryFactory) { return new RetryLoadBalancerInterceptor(loadBalancerClient, properties, requestFactory, loadBalancedRetryFactory); } @Bean @ConditionalOnMissingBean public RestTemplateCustomizer restTemplateCustomizer( final RetryLoadBalancerInterceptor loadBalancerInterceptor) { return restTemplate -> { List<ClientHttpRequestInterceptor> list = new ArrayList<>( restTemplate.getInterceptors()); list.add(loadBalancerInterceptor); restTemplate.setInterceptors(list); }; } } }
spring-cloud-commons-2.0.0.RC2-sources.jar!/org/springframework/cloud/client/loadbalancer/LoadBalancerRetryProperties.javaspring
/** * Configuration properties for the {@link LoadBalancerClient}. * @author Ryan Baxter */ @ConfigurationProperties("spring.cloud.loadbalancer.retry") public class LoadBalancerRetryProperties { private boolean enabled = true; /** * Returns true if the load balancer should retry failed requests. * @return true if the load balancer should retry failed request, false otherwise. */ public boolean isEnabled() { return enabled; } /** * Sets whether the load balancer should retry failed request. * @param enabled whether the load balancer should retry failed requests */ public void setEnabled(boolean enabled) { this.enabled = enabled; } }
spring-cloud-commons-2.0.0.RC2-sources.jar!/org/springframework/cloud/client/loadbalancer/RetryLoadBalancerInterceptor.javaide
public class RetryLoadBalancerInterceptor implements ClientHttpRequestInterceptor { private LoadBalancerClient loadBalancer; private LoadBalancerRetryProperties lbProperties; private LoadBalancerRequestFactory requestFactory; private LoadBalancedRetryFactory lbRetryFactory; public RetryLoadBalancerInterceptor(LoadBalancerClient loadBalancer, LoadBalancerRetryProperties lbProperties, LoadBalancerRequestFactory requestFactory, LoadBalancedRetryFactory lbRetryFactory) { this.loadBalancer = loadBalancer; this.lbProperties = lbProperties; this.requestFactory = requestFactory; this.lbRetryFactory = lbRetryFactory; } @Override public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException { final URI originalUri = request.getURI(); final String serviceName = originalUri.getHost(); Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri); final LoadBalancedRetryPolicy retryPolicy = lbRetryFactory.createRetryPolicy(serviceName, loadBalancer); RetryTemplate template = createRetryTemplate(serviceName, request, retryPolicy); return template.execute(context -> { ServiceInstance serviceInstance = null; if (context instanceof LoadBalancedRetryContext) { LoadBalancedRetryContext lbContext = (LoadBalancedRetryContext) context; serviceInstance = lbContext.getServiceInstance(); } if (serviceInstance == null) { serviceInstance = loadBalancer.choose(serviceName); } ClientHttpResponse response = RetryLoadBalancerInterceptor.this.loadBalancer.execute( serviceName, serviceInstance, requestFactory.createRequest(request, body, execution)); int statusCode = response.getRawStatusCode(); if (retryPolicy != null && retryPolicy.retryableStatusCode(statusCode)) { byte[] bodyCopy = StreamUtils.copyToByteArray(response.getBody()); response.close(); throw new ClientHttpResponseStatusCodeException(serviceName, response, bodyCopy); } return response; }, new LoadBalancedRecoveryCallback<ClientHttpResponse, ClientHttpResponse>() { //This is a special case, where both parameters to LoadBalancedRecoveryCallback are //the same. In most cases they would be different. @Override protected ClientHttpResponse createResponse(ClientHttpResponse response, URI uri) { return response; } }); } private RetryTemplate createRetryTemplate(String serviceName, HttpRequest request, LoadBalancedRetryPolicy retryPolicy) { RetryTemplate template = new RetryTemplate(); BackOffPolicy backOffPolicy = lbRetryFactory.createBackOffPolicy(serviceName); template.setBackOffPolicy(backOffPolicy == null ? new NoBackOffPolicy() : backOffPolicy); template.setThrowLastExceptionOnExhausted(true); RetryListener[] retryListeners = lbRetryFactory.createRetryListeners(serviceName); if (retryListeners != null && retryListeners.length != 0) { template.setListeners(retryListeners); } template.setRetryPolicy( !lbProperties.isEnabled() || retryPolicy == null ? new NeverRetryPolicy() : new InterceptorRetryPolicy(request, retryPolicy, loadBalancer, serviceName)); return template; } }
LoadBalancerAutoConfiguration這個類定義了LoadBalancerRequestFactory以及LoadBalancerInterceptor,另外主要配置的是loadBalancer的重試。重試功能主要經過spring retry組件的RetryTemplate來實現。ui