ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Spring Cloud教程 第三弹 Ribbon工作原理

2021-06-02 11:54:50  阅读:182  来源: 互联网

标签:Spring RestTemplate Bean LoadBalancerInterceptor Cloud LoadBalancerAutoConfigura


本文只介绍Ribbon的工作原理,关于Ribbon的其它教程请看这篇文章 Spring Cloud教程 第二弹 客户端负载均衡Ribbon 因为Ribbon的工作原理我写的有点细,篇幅稍大,所以单独抽出来了,没有将本文糅合在第二弹里。

更多Spring与微服务相关的教程请戳这里 Spring与微服务教程合集

 

1、揭开RestTemplate的神秘面纱

我们实际上关心的是,为什么@LoadBalanced注解能赋予RestTemplate负载均衡的能力?

关于Ribbon的核心工作原理,请小伙伴们一定要一步一步耐心往下看。

 

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

可以看到,RibbonAutoConfiguration加载于EurekaClientAutoConfiguration之前,加载于LoadBalancerAutoConfiguration之后

EurekaClientAutoConfiguration不必多说,引入Eureka Client必然会加载这个类

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

 

RibbonLoadBalancerClient主要为加载LoadBalancerAutoConfiguration服务,没有RibbonLoadBalancerClient这个Bean,后者无法加载,具体细节看下图。

 

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

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

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


 
这不就是我们很熟悉的那块代码嘛

@LoadBalanced注解与@Qualifier注解有关,关于@LoadBalanced注解的原理请看这篇文章 Ribbon中@LoadBalanced注解的原理

 

另外,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:

          2.1、ribbonInterceptor该方法声明了一个负载均衡拦截器的Bean,该方法有两个参数loadBalancerClient、LoadBalancerRequestFactory requestFactory,这两个参数都已经有了。而LoadBalancerInterceptor继承自ClientHttpRequestInterceptor,表明LoadBalancerInterceptor就是spring boot的一个拦截器

          2.2、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中的两个接口,如果想了解更多请看这篇文章 Spring Cloud教程 第二弹 客户端负载均衡Ribbon

request.apply方法的实现细节:

request对象是在LoadBalancerInterceptor的intercept方法中传过来的,具体如下图:

 

点进去看看,如下图:

 

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

 

总结

关于Ribbon的工作原理,我写的虽然有点多,但是很详细,耐心看完的话基本没有啥疑问的。当你读懂之后,发现Ribbon似乎不再神秘了

 

标签:Spring,RestTemplate,Bean,LoadBalancerInterceptor,Cloud,LoadBalancerAutoConfigura
来源: https://blog.51cto.com/u_14643435/2845389

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有