文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

SpringCloud负载均衡组件Ribbon源码分析

2023-07-02 18:34

关注

本文小编为大家详细介绍“SpringCloud负载均衡组件Ribbon源码分析”,内容详细,步骤清晰,细节处理妥当,希望这篇“SpringCloud负载均衡组件Ribbon源码分析”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

项目实战

创建项目

同样的,我们的项目现在依然有一个registry注册中心,一个provider服务提供者,接下来,我们再次修改一下consumer服务消费者的代码:

@EnableEurekaClient@SpringBootApplication@RestControllerpublic class ConsumerApplication {    public static void main(String[] args) {        SpringApplication.run(ConsumerApplication.class, args);    }    @Bean    @LoadBalanced    RestTemplate restTemplate() {        return new RestTemplate();    }    @Autowired    DiscoveryClient discoveryClient;    @Autowired    RestTemplate restTemplate;    @GetMapping("/hello2")    public String hello2(String name) {        String returnInfo = restTemplate.getForObject(  "http://provider/hello?name={1}", String.class, name);        return returnInfo;    }}

在这个版本,同样的,还是创建RestTemplate Bean对象,不同的是上面仅仅增加了@LoadBalanced注解。

启动项目验证

SpringCloud负载均衡组件Ribbon源码分析

依然正确返回了结果!

太神奇了吧,比我们自己开发的负载均衡组件简单太多了吧,仅仅在restTemplate() 方法上面增加了一个@LoadBalanced注解,怎么就实现的呢?废话不说,为了一探究竟,扒一扒源码吧!

源码分析

首先,点击@LoadBalanced注解进去,没有什么特别之处,那么我们在想想,Spring在创建Bean实例的时候,注解在什么地方起了作用?什么?不知道?翻一下这篇文章吧:

肝了两周,一张图解锁Spring核心源码

通过回顾Spring启动以及Bean的生命周期创建过程,我们就会发现加上@LoadBalancer注解后,项目启动时就会加载LoadBalancerAutoConfiguration这个配置类(通过spring-cloud-commons包下面的的spring.factories)。通过查看该配置类源码,发现其有个静态内部类LoadBalancerInterceptorConfig,其内部又创建了一个负载均衡拦截器:LoadBalancerInterceptor,该拦截器包含有一个loadBalancerClient参数:

@ConditionalOnMissingClass({"org.springframework.retry.support.RetryTemplate"})    static class LoadBalancerInterceptorConfig {        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);            };        }    }

我们继续点击LoadBalancerInterceptor类进入,发现intercept方法,该方法中调用了LoadBalancerClient的execute方法,

    public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException {        URI originalUri = request.getURI();        String serviceName = originalUri.getHost();        Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);        return (ClientHttpResponse)this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));    }

LoadBalancerClient是一个接口,点击进去我们发现其实现类是RibbonLoadBalancerClient,查看其继承关系:

SpringCloud负载均衡组件Ribbon源码分析

通过接口中的方法名称,我们可以猜想,choose方法就是选择其中服务列表中其中一个服务,reconstructURI方法就是重新构造请求的URI。

选择服务

choose方法是在RibbonLoadBalancerClient实现类中实现的

    public ServiceInstance choose(String serviceId, Object hint) {        Server server = this.getServer(this.getLoadBalancer(serviceId), hint);        return server == null ? null : new RibbonLoadBalancerClient.RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server));    }

在这个方法中,先调用 getServer 方法获取服务,这个方法最终会调用 ILoadBalancer 接口的 chooseServer 方法,而 ILoadBalancer 接口的实现类默认是ZoneAwareLoadBalancer。

ZoneAwareLoadBalancer 继承自 DynamicServerListLoadBalancer ,而在 DynamicServerListLoadBalancer 的构造方法中,调用了 this.restOfInit(clientConfig);在restOfInit这个方法中,通过 this.updateListOfServers()来获取服务列表;

而在chooseServer ()方法中,就会根据负载均衡算法,选择其中一个服务并返回:

 BaseLoadBalancer zoneLoadBalancer = this.getLoadBalancer(zone); server = zoneLoadBalancer.chooseServer(key);

地址替换

选择其中一个服务信息后,怎么将接口从 http://provider/hello 变为 http://localhost:8003/hello 呢?还记得上面我们说的reconstructURI方法吗?通过配置类LoadBalancerAutoConfiguration加载后,会注入LoadBalancerInterceptor拦截器,该拦截器会拦截我们的请求,并对请求地址进行处理,重构方法的具体实现在 LoadBalancerContext 类的 reconstructURIWithServer 方法中

public URI reconstructURIWithServer(Server server, URI original) {        String host = server.getHost();        int port = server.getPort();        String scheme = server.getScheme();        if (host.equals(original.getHost()) && port == original.getPort() && scheme == original.getScheme()) {            return original;        } else {            if (scheme == null) {                scheme = original.getScheme();            }            if (scheme == null) {                scheme = (String)this.deriveSchemeAndPortFromPartialUri(original).first();            }            try {                StringBuilder sb = new StringBuilder();                sb.append(scheme).append("://");                if (!Strings.isNullOrEmpty(original.getRawUserInfo())) {                    sb.append(original.getRawUserInfo()).append("@");                }                sb.append(host);                if (port >= 0) {                    sb.append(":").append(port);                }                sb.append(original.getRawPath());                if (!Strings.isNullOrEmpty(original.getRawQuery())) {                    sb.append("?").append(original.getRawQuery());                }                if (!Strings.isNullOrEmpty(original.getRawFragment())) {                    sb.append("#").append(original.getRawFragment());                }                URI newURI = new URI(sb.toString());                return newURI;            } catch (URISyntaxException var8) {                throw new RuntimeException(var8);            }        }    }

可以看到该方法中,将原始的请求地址original,替换成了选取的服务的IP和端口。并最终调用该服务的接口方法。

读到这里,这篇“SpringCloud负载均衡组件Ribbon源码分析”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯