zoukankan      html  css  js  c++  java
  • 读书笔记-Ribbon源码分析

    @LoadBalanced注解用来给RestTemplate做标记,以使用负载均衡的客户端来配置。

    通过搜索LoadBalancerClient可以发现,LoadBalancerClient是SpringCloud定义的一个接口

    public interface LoadBalancerClient {
    Serviceinstance choose(String serviceId);
    <T> T execute(String serviceid, LoadBalancerRequest<T> request) throws
    IOException;
    URI reconstructURI(Serviceinstance instance, URI original);

    }

    通过该接口,了解客户端负载均衡器因该具备几种能力。

    1.choose(String serviceId):根据传入的服务名serviceId,从负载均衡器中挑选一个对应的服务实例。

    2.<T> T execute(String serviceid, LoadBalancerRequest<T> request):使用从负载均衡器中挑选服务实例来执行请求内容。

    3.URI reconstructURI(Serviceinstance instance, URI original);:为系统构建一个合适的host:port形式的URI。在分布式系统中,我们使用逻辑上的服务名作为host来构建URI进行请求 。

    LoadBalancerAutoConfiguration 类为实现客户端负载均衡的自动化配置类。通过查看配置类的源码。可以知道Ribbon实现的负载均衡自动化配置需要满足下面两个条件。

    1.RestTemplate类必须存在于当前工程的环境中。

    2.在Spring的Bean工程中必须有LoadBalancerClient的实现的Bean。

    在改自动化配置类中,主要做了下面三个事:

    1.创建了一个LoadBalancerInterceptor的Bean,用于实现客户端发起请求进行拦截,以实现客户端的负载均衡。

    2.创建一个RestTemplateCustomizer的Bean,用于给RestTemplate增加LoadBalancerInterceptor拦截器。

    3.维护了一个被@LoadBalanced注释修饰的RestTemplate对象列表。并在这里进行初始化,通过调用RestTemplateCustomizer的实例来给需要客户端负载均衡的RestTemplate增加LoadBalancerInterceptor拦截器。

    通过源码分析,拦截器注入了LoadBalancerClient的实现,当一个被@LoadBalanced注解修饰的RestTemplate对象想外发起HTTP请求时,会被LoadBalancerInterceptor类的intercept函数所拦截。由于我们在使用RestTemplate时采用了服务名作为host,所以直接从HttpRequest的URI对象中通过getHost()就可以拿到服务名。然后调用execute函数去根据服务名来选择实例并发起实际的请求。

    以上的LoadBalancerClient还只是一个抽象的负载均衡器接口,所以我们还需要找到他的具体实现类来进一步进行分析。他的具体实现类是RibbonLoadBalancerClient。

    在RibbonLoadBalancerClient的execute函数实现中,第一步就是通过getServer根据传入的服务名serviceId去获得具体的服务实例。

    SpringCloud默认财通了ZoneAwareLoadBalancer来实现负载均衡器。

    通过ZoneAwareLoadBalancer的chooseServer函数获取了负载均衡策略分配到的服务实例对象Server之后,还将起对象包装成RibbonServer对象(该对象处理存储了服务实例的对象之外,还增加了服务名serviceId,是否需要使用HTTPS等其他信息),然后使用该对象在回调LoadBalancerInterceptor请求拦截器中LoadBalancerRequest的apply函数,向一个世纪的具体服务实例发起请求,从而实现一开始以服务名为host的URI请求到host:post形式的实际访问地址的转换。

    在apply函数中传入的ServiceInstance接口对象是对服务实例的抽象定义,在改接口暴露了服务治理系统中每个服务实例需要提供的一些基本信息。比如serviceId,host,post等,具体定义如下。

    public interface ServiceInstance {
        String getServiceId();
    
        String getHost();
    
        int getPort();
    
        boolean isSecure();
    
        URI getUri();
    
        Map<String, String> getMetadata();
    }
    

      上面提到的具体包装Server服务实例的RibbonServer对象就是ServiceInstance接口的实现,可以看到他除了包装Server对象之外,还存储了服务名,是否使用HTTPS标识以及一个Map类型的元数据集合。

    从apply的实现中,可以看到他具体执行的时候,还传入了ServiceRequestWrapper对象,该对象继承了HttpRequestWrapper并重写了getURI函数,重写后的getURI通过调用LoadBalancerClient接口的reconstructURI函数来重新构建一个URI来进行访问。

  • 相关阅读:
    JAVA规范
    JMS开发指南
    JMS异步消息机制
    大型系统中使用JMS优化技巧–Sun OpenMQ
    02.MyBatis配置文件详解
    elasticsearch.yml配置文件
    04.ActiveMQ与Spring JMS整合
    01.MyBatis入门
    03.JMS深入
    02.JMS基础
  • 原文地址:https://www.cnblogs.com/caobojia/p/8528785.html
Copyright © 2011-2022 走看看