当前位置: 首页 > news >正文

聊聊spring cloud的LoadBalancerAutoConfiguration

本文主要研究一下spring cloud的LoadBalancerAutoConfiguration

RibbonAutoConfiguration

spring-cloud-netflix-ribbon-2.0.0.RC2-sources.jar!/org/springframework/cloud/netflix/ribbon/RibbonAutoConfiguration.java

@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);
            };
        }
    }
}
  • 定义了LoadBalancerRequestFactory以及LoadBalancerInterceptorConfig、RetryAutoConfiguration、RetryInterceptorAutoConfiguration

LoadBalancerRetryProperties

spring-cloud-commons-2.0.0.RC2-sources.jar!/org/springframework/cloud/client/loadbalancer/LoadBalancerRetryProperties.java

/**
 * 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;
    }
}
  • 这个配置是否开启loadbalancer的retry

RetryLoadBalancerInterceptor

spring-cloud-commons-2.0.0.RC2-sources.jar!/org/springframework/cloud/client/loadbalancer/RetryLoadBalancerInterceptor.java

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;
    }
}
  • 实现了ClientHttpRequestInterceptor接口
  • 通过lbRetryFactory.createRetryPolicy(serviceName,loadBalancer)创建重试策略,然后创建RetryTemplate

小结

LoadBalancerAutoConfiguration这个类定义了LoadBalancerRequestFactory以及LoadBalancerInterceptor,另外主要配置的是loadBalancer的重试。重试功能主要通过spring retry组件的RetryTemplate来实现。

doc

  • Spring Cloud Finchley.RELEASE Documentation

相关文章:

  • devops
  • Angular Elements 及其运作原理
  • 切蛋糕
  • solr常见异常解决办法
  • 细说Cookie
  • 路径
  • 颜色直方图比较数据
  • JVM调优总结(5):典型配置
  • python 之 进程池与线程池
  • 经典正则表达式 (收藏整理)
  • 前端工程师最好的全栈开发实践-设计开发属于自己的nodejs博客
  • eclipse创建android项目出现error libz.so.1: cannot open shared object file:No such file or directory...
  • 回溯法----背包问题
  • FTP攻略
  • __dopostback的用法
  • 自己简单写的 事件订阅机制
  • 【附node操作实例】redis简明入门系列—字符串类型
  • ECMAScript入门(七)--Module语法
  • Java 最常见的 200+ 面试题:面试必备
  • php面试题 汇集2
  • windows下使用nginx调试简介
  • 基于组件的设计工作流与界面抽象
  • 解决jsp引用其他项目时出现的 cannot be resolved to a type错误
  • 前端存储 - localStorage
  • 前端知识点整理(待续)
  • 山寨一个 Promise
  • 使用阿里云发布分布式网站,开发时候应该注意什么?
  • 我的面试准备过程--容器(更新中)
  • 验证码识别技术——15分钟带你突破各种复杂不定长验证码
  • 一个6年java程序员的工作感悟,写给还在迷茫的你
  • 一起来学SpringBoot | 第三篇:SpringBoot日志配置
  • 移动端唤起键盘时取消position:fixed定位
  • 阿里云ACE认证之理解CDN技术
  • 扩展资源服务器解决oauth2 性能瓶颈
  • ​软考-高级-系统架构设计师教程(清华第2版)【第9章 软件可靠性基础知识(P320~344)-思维导图】​
  • ###C语言程序设计-----C语言学习(3)#
  • #使用清华镜像源 安装/更新 指定版本tensorflow
  • (02)Hive SQL编译成MapReduce任务的过程
  • (06)金属布线——为半导体注入生命的连接
  • (14)学习笔记:动手深度学习(Pytorch神经网络基础)
  • (4)Elastix图像配准:3D图像
  • (6)添加vue-cookie
  • (Pytorch框架)神经网络输出维度调试,做出我们自己的网络来!!(详细教程~)
  • (二)PySpark3:SparkSQL编程
  • (翻译)Entity Framework技巧系列之七 - Tip 26 – 28
  • (附源码)spring boot公选课在线选课系统 毕业设计 142011
  • (附源码)ssm本科教学合格评估管理系统 毕业设计 180916
  • (规划)24届春招和25届暑假实习路线准备规划
  • (算法)求1到1亿间的质数或素数
  • (译) 理解 Elixir 中的宏 Macro, 第四部分:深入化
  • (原創) 如何使用ISO C++讀寫BMP圖檔? (C/C++) (Image Processing)
  • (自用)learnOpenGL学习总结-高级OpenGL-抗锯齿
  • .NET 4 并行(多核)“.NET研究”编程系列之二 从Task开始
  • .NET Core 成都线下面基会拉开序幕
  • .NET/C# 使用反射调用含 ref 或 out 参数的方法