Spring Cloud Ribbon 分析(二)之LoadBalancerAutoConfiguration负载均衡配置

Spring Cloud Ribbon 分析(一)之RibbonAutoConfiguration中我们分析了入口配置类的相关介绍,本节介绍LoadBalancerAutoConfiguration这个配置类以及该配置具体作用!


LoadBalancerAutoConfiguration

@AutoConfigureBefore({LoadBalancerAutoConfiguration.class, AsyncLoadBalancerAutoConfiguration.class})
@EnableConfigurationProperties({RibbonEagerLoadProperties.class, ServerIntrospectorProperties.class})
public class RibbonAutoConfiguration {
    ......
}

LoadBalancerAutoConfiguration在RibbonAutoConfiguration之后被装配

@Configuration
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {

    @LoadBalanced
    @Autowired(required = false)
    private List restTemplates = Collections.emptyList();

    @Bean
    public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
            final ObjectProvider> restTemplateCustomizers) {
        return () -> restTemplateCustomizers.ifAvailable(customizers -> {
            for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
                for (RestTemplateCustomizer customizer : customizers) {
                    customizer.customize(restTemplate);
                }
            }
        });
    }
    ......
    @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 list = new ArrayList<>(
                        restTemplate.getInterceptors());
                list.add(loadBalancerInterceptor);
                restTemplate.setInterceptors(list);
            };
        }
    }
}

依赖RestTemplate类、LoadBalancerClient实例,然后我们看到里面比较重要的地方private List restTemplates = Collections.emptyList();被标注了@LoadBalanced这个注解,这个注解有什么用呢?


@LoadBalanced

/**
 * 标记RestTemplate实例,让RestTemplate具备负载作用
 */
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {
}

此处我们注意@Qualifier这个注解,这个注解我们一般用的最多的场景可能是在多个实例Bean都实现了同一个interface接口,我们在使用这些实例的时候,Spring容器会提示我们有多个实例,需要使用者显示给Bean对象赋予具体的名字,然后我们在回头看看这个LoadBalanced注解被标注了这个@Qualifier,那我们可以理解为@LoadBalanced其实是@Qualifier的一个子类,如果还不是很清楚这个原理,我们索性就直接可以理解@LoadBalanced注解其实就是@Qualifier注解,这样就一目了然了

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

    @LoadBalanced
    @Autowired(required = false)
    private List restTemplates = Collections.emptyList();

我们这样注册实例时候之后,然后我们的RestTemplate就被扫描到了restTemplates对象中,此时还没有负载的作用


RetryLoadBalancerInterceptor

public class RetryLoadBalancerInterceptor implements ClientHttpRequestInterceptor {

    private LoadBalancerClient loadBalancer;
    private LoadBalancerRetryProperties lbProperties;
    private LoadBalancerRequestFactory requestFactory;
    private LoadBalancedRetryFactory lbRetryFactory;

    ......

    @Override
    public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
                                        final ClientHttpRequestExecution execution) throws IOException {
        ......
        return template.execute(context -> {
            ServiceInstance serviceInstance = null;
            if (context instanceof LoadBalancedRetryContext) {
                LoadBalancedRetryContext lbContext = (LoadBalancedRetryContext) context;
                serviceInstance = lbContext.getServiceInstance();
            }
            if (serviceInstance == null) {
                //从负载均衡器中获取一个可用的服务(通过RibbonLoadBalancerClient获取可用服务)
                serviceInstance = loadBalancer.choose(serviceName);
            }
            //执行负载均衡器的execute获取结果(通过RibbonLoadBalancerClient获取可用服务)
            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() {
            @Override
            protected ClientHttpResponse createResponse(ClientHttpResponse response, URI uri) {
                return response;
            }
        });
    }
}

从注释信息我们可以得知拦截类主要做了两件事情,loadBalancer.choose和loadBalancer.execute,此时这个拦截类并没有设置给RestTemplate对象,此时我们在看看下面的片段,我们就比较清晰了

    @Bean
    @ConditionalOnMissingBean
    public RestTemplateCustomizer restTemplateCustomizer(
            final RetryLoadBalancerInterceptor loadBalancerInterceptor) {
        return restTemplate -> {
            List list = new ArrayList<>(
                    restTemplate.getInterceptors());
            list.add(loadBalancerInterceptor);
            restTemplate.setInterceptors(list);
        };
    }

    @Bean
    public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
            final ObjectProvider> restTemplateCustomizers) {
        return () -> restTemplateCustomizers.ifAvailable(customizers -> {
            for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
                for (RestTemplateCustomizer customizer : customizers) {
                    customizer.customize(restTemplate);
                }
            }
        });
    }

先注册了RestTemplateCustomizer实例,Bean实例化完成,包括依赖注入完成,BeadPostProcess,InitializingBean,initMethod等等全部完成后在执行SmartInitializingSingleton
可以理解为Bean的收尾操作,这样就会回调RestTemplateCustomizer的restTemplate.setInterceptors(list),这样就完成了给所有标记了@LoadBalanced注解的RestTemplate对象设置拦截器,就具备了负载的作用


在分析一中提到RibbonLoadBalancerClient,那这个类是怎么用起来的呢?通过什么方式才能被用起来?这样一来,其实总结就是RibbonLoadBalancerClient&RestTemplate结合起来使用,在Spring Cloud Ribbon 分析(三)之RibbonClientConfiguration我们会介绍Ribbon客户端的相关分析!

你可能感兴趣的:(Spring Cloud Ribbon 分析(二)之LoadBalancerAutoConfiguration负载均衡配置)