首页 > 编程语言 >【Spring Cloud】Ribbon工作原理源码剖析

【Spring Cloud】Ribbon工作原理源码剖析

时间:2023-04-15 11:23:20浏览次数:41  
标签:Spring RestTemplate final Bean 源码 LoadBalancerInterceptor LoadBalancerAutoConfig

Ribbon调用流程

Ribbon工作原理

为什么@LoadBalanced注解能赋予RestTemplate负载均衡的能力?

Ribbon组件在启动时,会自动加载RibbonAutoConfiguration这个配置类,如下图

RibbonAutoConfiguration加载于EurekaClientAutoConfiguration之前,加载于LoadBalancerAutoConfiguration之后

引入Eureka Client必然会加载EurekaClientAutoConfiguration这个类

而RibbonAutoConfiguration中声明了这样的一个Bean,如下图:

RibbonLoadBalancerClient主要为加载LoadBalancerAutoConfiguration服务,没有RibbonLoadBalancerClient这个Bean,后者无法加载,如下图:

下面主要就来看看LoadBalancerAutoConfiguration这个类做了什么事情

首先,LoadBalancerAutoConfiguration有这样一块代码:

这块代码表示的含义是:将所有用@LoadBalanced注解标识的RestTemplate类型的Bean注入到List集合中,而恰好我们的确也声明了这样的一个Bean,如下图所示:

另外,LoadBalancerAutoConfiguration类中还有另外几块重要的代码:

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


    @Bean
    @ConditionalOnMissingBean
    public LoadBalancerRequestFactory loadBalancerRequestFactory(
        LoadBalancerClient loadBalancerClient) {
        return new LoadBalancerRequestFactory(loadBalancerClient, this.transformers);
    }

    @Configuration(proxyBeanMethods = false)
    @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 -> {
                Listlist = new ArrayList<>(
                    restTemplate.getInterceptors());
                list.add(loadBalancerInterceptor);
                restTemplate.setInterceptors(list);
            };
        }

    }

}

1)loadBalancerRequestFactory方法用于声明一个负载均衡请求生成工厂

2)LoadBalancerInterceptorConfig 这个内部静态类声明了两个Bean:

  • loadBalancerInterceptor:该方法声明了一个负载均衡拦截器的Bean,该方法有两个参数loadBalancerClient、LoadBalancerRequestFactory requestFactory,这两个参数都已经有了。而LoadBalancerInterceptor继承自ClientHttpRequestInterceptor,表明LoadBalancerInterceptor就是spring boot的一个拦截器。
  • restTemplateCustomizer:该方法用于声明一个RestTemplateCustomizer类型的Bean。该bean的目的在于:将RestTemplate与LoadBalancerInterceptor绑定起来,这是RestTemplate具有负载均衡能力的关键

3)loadBalancedRestTemplateInitializerDeprecated方法用于触发RestTemplateCustomizer这个Bean的执行

综上所述,RestTemplate发出的请求最后是被LoadBalancerInterceptor这个拦截器拦截到了,下面看一下LoadBalancerInterceptor的intercept方法主要做了哪些事情:

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

最终的请求交由loadBalancer这个负载均衡器执行,this.loadBalancer的类型是LoadBalancerClient,而LoadBalancerClient的实现为RibbonLoadBalancerClient,LoadBalancerClient继承自ServiceInstanceChooser接口

public interface ServiceInstanceChooser {
    ServiceInstance choose(String serviceId);
}

通过this.loadBalancer.execute这行代码往里面跟踪,找到最终的执行方法如下(execute-1会调用execute-2):

getServer方法的实现细节:ILoadBalancer的chooseServer方法会转换为调用IRule的choose方法。ILoadBalancer和IRule是Ribbon中的两个接口

request.apply方法的实现细节:request对象是在LoadBalancerInterceptor的intercept方法中传过来的。

最后的execution.execute方法是执行最终的http请求的地方,至此,一次ribbon的生命周期就到此结束了。

 

标签:Spring,RestTemplate,final,Bean,源码,LoadBalancerInterceptor,LoadBalancerAutoConfig
From: https://www.cnblogs.com/xfeiyun/p/17320699.html

相关文章

  • Springboot-2
    1.springboot自动装配原理1.1springboot包扫描原理包建议放在主类所在包或者子包。默认包扫描的是主类所在的包以及子包。主函数运行时会加载使用@SpringBootApplication标记的类,-->包含@SpringBootApplication-->@EnableAutoConfiguration-->@AutoConfigurationPackage--......
  • 源码共读 | axios 工具函数
    前言Axios是一个非常流行的库,它可以让你简单、方便地发送HTTP请求。它可以用在浏览器和node.js中,并且支持跨域请求。在Github上拥有快接近10w颗星了,可见其受欢迎程度。下面就来学习一下axios工具函数的源码。仓库地址:axios/axios:PromisebasedHTTPclientfortheb......
  • #yyds干货盘点#Spring事务回滚的两种方法
    Spring事务回滚的前提是你当前使用的数据库必须支持事务,比如MySQL的Innodb是支持的,但Mysaim则是不支持事务的。方法一使用@Transaction来配置自动回滚,可以配置在类上,也可以配置在方法上(作用域不同),但对final或private修饰的方法无效,且该类必须是受spring所管控的,也就是被已经被注......
  • springboot连接不同数据库的写法
    MySQL当url连接不指定/数据库名可以访问到mysql服务器上有权限的任何库,但是所有sql需要加上库名前缀.pom<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency>配置spring:datasource:driver-class-n......
  • SpringBoot 集成 MybatisPlus 九——逻辑删除
    1逻辑删除的概念逻辑删除不会在数据库中删除数据,只是通过一个字段用来标识被删除的记录,数据仍然保存在数据库中。在实际的工作当中,因为数据非常重要,为了防止因用户误操作删除数据后无法恢复的问题,我们通常不会对数据做物理删除,即将数据从数据库中直接删除。而是多采用逻辑删除的方......
  • Go For Web:Golang http 包详解(源码剖析)
    前言:本文作为解决如何通过Golang来编写Web应用这个问题的前瞻,对Golang中的Web基础部分进行一个简单的介绍。目前Go拥有成熟的Http处理包,所以我们去编写一个做任何事情的动态Web程序应该是很轻松的,接下来我们就去学习了解一些关于Web的相关基础,了解一些概念,以及......
  • SpringSecurity过滤器-CsrfFilter
    CsrfFilter是为了防御CSRF攻击的。CSRF攻击请参考松哥手把手教你在SpringBoot中防御CSRF攻击!soeasy!。CsrfFilter的源码在要学就学透彻!SpringSecurity中CSRF防御源码解析说的很清楚了。 在这里是对LazyCsrfTokenRepository的使用做个总结。 CsrfFilter#doFilterI......
  • vue2源码-五、将模板编译解析成AST语法树1
    将模板编译成ast语法树complileToFunction方法vue数据渲染:template模板->ast语法树->render函数,模板编译的最终结果结果就是render函数。在complileToFunction方法中,生成render函数,需要以下两个核心步骤:通过parserHTML方法:将模板(template或html)内容编译成ast语法树通过co......
  • SpringBoot常用注解
    本文整理了SpringBoot常用注解,主要讲解这些注解的用法,并附上一致思维导图。SpringBoot常用注解组件相关注解@Controller用于修饰MVC中controller层的组件,SpringBoot中的组件扫描功能会识别到该注解,并为修饰的类实例化对象,通常与@RequestMapping联用,当SpringMVC获取到请求时......
  • 解决Spring Boot jar包启动日志输出中文乱码
    在使用slf4j做日志输出时,打jar包运行后,会出现中文乱码问题,只需要将logback-spring.xml配置文件中的<charset>标签注释即可,如图:  解释: 如果不配置logback-spring.xml或resource文件夹下没有logback-spring.xml文件,则springboot使用默认的配置,那么部署jar包,java-jarxxx.......