Ribbon -学习源码解析

Ribbon- 学习源码解析

标记RestTemplate对象

当我们使用@LoadBalanced标签对我们调用微服务提供方接口的RestTemplate类做注解的时候。

这一步就是其实在标签里什么都没做,只是在spring容器中的RestTemplate对象打了一个标记。

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

Spring 容器启动时找相关的spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration

Spring自动装配了RibbonAutoConfiguration

找到这个类还做了@AutoConfigureBefore的注解并且包含了LoadBalancerAutoConfiguration.class

@Configuration
@Conditional({RibbonAutoConfiguration.RibbonClassesConditions.class})
@RibbonClients
@AutoConfigureAfter(
    name = {"org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration"}
)
@AutoConfigureBefore({LoadBalancerAutoConfiguration.class, AsyncLoadBalancerAutoConfiguration.class})
@EnableConfigurationProperties({RibbonEagerLoadProperties.class, ServerIntrospectorProperties.class})
public class RibbonAutoConfiguration {
    @Autowired(
        required = false
    )
    private List<RibbonClientSpecification> configurations = new ArrayList();
    @Autowired
    private RibbonEagerLoadProperties ribbonEagerLoadProperties;

    public RibbonAutoConfiguration() {
    }

转到LoadBalancerAutoConfiguration

这个类中有@ConditionalOnClass(RestTemplate.class) 表示判断当前classpath下是否存在指定类RestTemplate.class,若存在则将当前被注解的配置LoadBalancerAutoConfiguration装载入spring容器

当然他还有@ConditionalOnBean(LoadBalancerClient.class) 表示判断当前context下是否存在指定beanLoadBalancerClient.class,若有则将当前被注解的配置LoadBalancerAutoConfiguration装载入spring容器

@Configuration
@ConditionalOnClass({RestTemplate.class})
@ConditionalOnBean({LoadBalancerClient.class})
@EnableConfigurationProperties({LoadBalancerRetryProperties.class})
public class LoadBalancerAutoConfiguration {
    @LoadBalanced
    @Autowired(
        required = false
    )
    private List<RestTemplate> restTemplates = Collections.emptyList();
    @Autowired(
        required = false
    )

执行封装新的interceptor

下面就是关键方法,在容器中找到所有restTemplate bean,获取它上面的所有Interceptor。

然后将我们的loadBalancerInterceptor给加进去。

当然,在这个类中还加进去了一个叫做RetryLoadBalancerInterceptor的intercepotr

这两段代码分别在两个不同的静态代码块里面

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

当restTemplate开始请求

product = restTemplate.getForObject("http://service-product/product/" + id,Product.class);
  • 不是马上执行API调用,而是会走到拦截器中,其中一个就是LoadBalancerInterceptor

  • 在LoadBalancerInterceptor.intercept里面使用LoadBalancerClient执行loadBalancer.execute

    return (ClientHttpResponse)this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));
    
  • 调转到RibbonLoadBalancerClient,在execute方法中通过serviceID获得一个ILoadBalancer (负载均衡器)

    ILoadBalancer loadBalancer = this.getLoadBalancer(serviceId);
    
  • 传入ILoadBalancer和hint执行getServer获取到真正带执行的server, 下面显示getServer的逻辑流程

    • 当ILoadBalancer不为空,将ILoadBalancer和hint对象传入BaseLoadBalancer的chooseServer方法
    • 在chooseServer中先增加counter记数,
    • 通过找到不同的rule的配置并传入hint通过负载均衡策略的choose方法得到server

    choose方法不同负载均衡策略的实现不同,有兴趣的朋友可以去看看每个rule的策略算法是怎样的。

    Server server = this.getServer(loadBalancer, hint);
    
    protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
            return loadBalancer == null ? null : loadBalancer.chooseServer(hint != null ? hint : "default");
        }
    
        public Server chooseServer(Object key) {
            if (this.counter == null) {
                this.counter = this.createCounter();
            }
    
            this.counter.increment();
            if (this.rule == null) {
                return null;
            } else {
                try {
                    return this.rule.choose(key);
                } catch (Exception var3) {
                    logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", new Object[]{this.name, key, var3});
                    return null;
                }
            }
        }
    
  • 将获得的server作为初始化参数创建ribbonServer

    RibbonLoadBalancerClient.RibbonServer ribbonServer = new RibbonLoadBalancerClient.RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server));
    
  • 传入ribbonServer执行真正的execute

        public <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException {
            Server server = null;
            if (serviceInstance instanceof RibbonLoadBalancerClient.RibbonServer) {
                server = ((RibbonLoadBalancerClient.RibbonServer)serviceInstance).getServer();
            }
    
            if (server == null) {
                throw new IllegalStateException("No instances available for " + serviceId);
            } else {
                RibbonLoadBalancerContext context = this.clientFactory.getLoadBalancerContext(serviceId);
                RibbonStatsRecorder statsRecorder = new RibbonStatsRecorder(context, server);
    
                try {
                    T returnVal = request.apply(serviceInstance);
                    statsRecorder.recordStats(returnVal);
                    return returnVal;
                } catch (IOException var8) {
                    statsRecorder.recordStats(var8);
                    throw var8;
                } catch (Exception var9) {
                    statsRecorder.recordStats(var9);
                    ReflectionUtils.rethrowRuntimeException(var9);
                    return null;
                }
            }
        }
    

附录

注解ConditionalOnXXX
@ConditionalOnBean         //   当给定的在bean存在时,则实例化当前Bean
@ConditionalOnMissingBean  //   当给定的在bean不存在时,则实例化当前Bean
@ConditionalOnClass        //   当给定的类名在类路径上存在,则实例化当前Bean
@ConditionalOnMissingClass //   当给定的类名在类路径上不存在,则实例化当前Bean
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值