程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长


+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

Ribbon之自动装配下ribbon做了些什么?(一)

发布于2021-06-12 14:13     阅读(472)     评论(0)     点赞(9)     收藏(5)


1.前言

在springboot的自动装配原理上,我们知道要使用一个组件,那么先去找spring.factories ,所以这里我们直接开始看spring-cloud-netflix-ribbon-2.1.0spring.factories 文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XjZUsAQE-1623313573279)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/2bc68058-9396-4534-9aac-99c622e44590/Untitled.png)]



2.RibbonAutoConfiguration 源码简读


@Configuration
// 这个是判断条件的集合,只有RibbonClassesConditions里面的条件都满足了才能实例化这个配置类
// 到spring 容器中去
@Conditional(RibbonAutoConfiguration.RibbonClassesConditions.class)
// 这个主要是为了注入RibbonClientConfigurationRegistrar,这个类后面详细解析一下
@RibbonClients
// 这个意思就是eureka client 装配完成后,才会装配Ribbon。这是因为ribbon要依赖eureka
@AutoConfigureAfter(name = "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration")
/// 在ribbon自动装配完后,继续装配LoadBalancerAutoConfiguration 和AsyncLoadBalancerAutoConfiguration 
 // 这两个类挺核心的,后面详细讲讲
@AutoConfigureBefore({LoadBalancerAutoConfiguration.class, AsyncLoadBalancerAutoConfiguration.class})
// 从spring的配置文件中读取配置信息到指定类中
@EnableConfigurationProperties({RibbonEagerLoadProperties.class, ServerIntrospectorProperties.class})
public class RibbonAutoConfiguration {

	@Autowired(required = false)
	private List<RibbonClientSpecification> configurations = new ArrayList<>();

	@Autowired
	private RibbonEagerLoadProperties ribbonEagerLoadProperties;

	@Bean
	public HasFeatures ribbonFeature() {
		return HasFeatures.namedFeature("Ribbon", Ribbon.class);
	}

	@Bean
	public SpringClientFactory springClientFactory() {
		SpringClientFactory factory = new SpringClientFactory();
		factory.setConfigurations(this.configurations);
		return factory;
	}

	// 创建ribbon负载均衡器客户端
	@Bean
	@ConditionalOnMissingBean(LoadBalancerClient.class)
	public LoadBalancerClient loadBalancerClient() {
		return new RibbonLoadBalancerClient(springClientFactory());
	}

	// 创建重试型ribbon 负载均衡器生产工厂
	// 存在两种发消息的工具,一种是RestTemplate,还有一种是RetryTemplate
	// 针对不同的需求,去创建不同的负载均衡器工厂
	@Bean
	@ConditionalOnClass(name = "org.springframework.retry.support.RetryTemplate")
	@ConditionalOnMissingBean
	public LoadBalancedRetryFactory loadBalancedRetryPolicyFactory(final SpringClientFactory clientFactory) {
		return new RibbonLoadBalancedRetryFactory(clientFactory);
	}

	@Bean
	@ConditionalOnMissingBean
	public PropertiesFactory propertiesFactory() {
		return new PropertiesFactory();
	}

	// 饿汉式加载 ribbon client
	@Bean
	@ConditionalOnProperty(value = "ribbon.eager-load.enabled")
	public RibbonApplicationContextInitializer ribbonApplicationContextInitializer() {
		return new RibbonApplicationContextInitializer(springClientFactory(),
				ribbonEagerLoadProperties.getClients());
	}

	@Configuration
	@ConditionalOnClass(HttpRequest.class)
	@ConditionalOnRibbonRestClient // 这个就在下面有定义
	protected static class RibbonClientHttpRequestFactoryConfiguration {

		@Autowired
		private SpringClientFactory springClientFactory;

		// restTemplate 定制化器
		@Bean
		public RestTemplateCustomizer restTemplateCustomizer(
				final RibbonClientHttpRequestFactory ribbonClientHttpRequestFactory) {
			// 设置为RibbonClientHttpRequestFactory 创建restTemplate
			return restTemplate -> restTemplate.setRequestFactory(ribbonClientHttpRequestFactory);
		}

		@Bean
		public RibbonClientHttpRequestFactory ribbonClientHttpRequestFactory() {
			return new RibbonClientHttpRequestFactory(this.springClientFactory);
		}
	}

	//TODO: support for autoconfiguring restemplate to use apache http client or okhttp

	@Target({ ElementType.TYPE, ElementType.METHOD })
	@Retention(RetentionPolicy.RUNTIME)
	@Documented
	// ribbon.http.client.enabled 判断是否开启ribbon.http.client.enabled 这个是zuul使用的
	// ribbon.restclient.enabled  判断是否开启ribbon.restclient.enabled 这个是ribbon使用的
	@Conditional(OnRibbonRestClientCondition.class)
	@interface ConditionalOnRibbonRestClient { }

	// 加载条件集合
	private static class OnRibbonRestClientCondition extends AnyNestedCondition {
		public OnRibbonRestClientCondition() {
			super(ConfigurationPhase.REGISTER_BEAN);
		}

		@Deprecated 
		@ConditionalOnProperty("ribbon.http.client.enabled")
		static class ZuulProperty {}
		
		@ConditionalOnProperty("ribbon.restclient.enabled")
		static class RibbonProperty {}
	}

	/**
	 * {@link AllNestedConditions} that checks that either multiple classes are present
	 * 当下面多个条件都满足的情况下,才会加载ribbon
	 */
	static class RibbonClassesConditions extends AllNestedConditions {

		RibbonClassesConditions() {
			super(ConfigurationPhase.PARSE_CONFIGURATION);
		}

		@ConditionalOnClass(IClient.class)
		static class IClientPresent {

		}

		@ConditionalOnClass(RestTemplate.class)
		static class RestTemplatePresent {

		}

		@ConditionalOnClass(AsyncRestTemplate.class)
		static class AsyncRestTemplatePresent {

		}

		@ConditionalOnClass(Ribbon.class)
		static class RibbonPresent {

		}

	}
}

上面源码总结有以下几点:

1.从 @AutoConfigureAfter(name = "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration") 注解发现RibbonAutoConfiguration是依赖于EurekaClientAutoConfiguration 的。


2. LoadBalancerAutoConfigurationAsyncLoadBalancerAutoConfiguration 这两个类在后面装配,说明需要依赖RibbonAutoConfiguration创建的东西


3. RibbonClassesConditionsRibbonAutoConfiguration 装配的前提条件,里面是多个条件的集合


4. SpringClientFactory 这个工厂类是用于创建ribbon client 客户端,load balancer 负载均衡器,客户端配置实例对象的。


5. 创建了一个持有springClientFactory对象的负载均衡器客户端LoadBalancerClient


6.LoadBalancedRetryFactory 如果开启重试功能,那么需要创建一个负责创建重试负载均衡器的工厂。


7.RibbonApplicationContextInitializer ribbon client 饿汉式加载。就是启动完就把ribbon client全部 初始化好


8. RibbonClientHttpRequestFactoryConfiguration 这个做了两件事,
第一个通过RestTemplateCustomizer 定制化了RestTemplate
第二个初始化定制RestTemplate的工厂RibbonClientHttpRequestFactory



3.LoadBalancerAutoConfiguration 在RibbonAutoConfiguration之后装配,那他又在做什么?

1.restTemplate 作为spring cloud feign的通讯工具,在这里会被特殊处理来达到负载均衡的目的

	
	@LoadBalanced // 注解标记这些restTemplate 会使用负载均衡客户端
	@Autowired(required = false) // RestTemplate 自动注入
	private List<RestTemplate> restTemplates = Collections.emptyList();

2.定制化RestTemplate集合,主要是为每个restTemplate注入ribbon的factory。

	// 这里对restTemplates 进行多个定制化器处理 
	@Bean
	public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
			final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
		return () -> restTemplateCustomizers.ifAvailable(customizers -> {
            for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
                for (RestTemplateCustomizer customizer : customizers) {
                    customizer.customize(restTemplate);
                }
            }
        });
	}

3.负载均衡请求转化器

	// http请求中加上服务实例信息
	@Autowired(required = false)
	private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();


4. 请求转换工厂,将HttpRequest转换为包含服务实例信息的HttpRequest
	// 负载均衡器工厂
	// 负责为LoadBalancerInterceptor和RetryLoadBalancerInterceptor创建LoadBalanceRequest
	// 应用LoadBalancerRequestTransformer 请求转换器到被拦截的HttpRequest请求中去。
	@Bean
	@ConditionalOnMissingBean
	public LoadBalancerRequestFactory loadBalancerRequestFactory(
			LoadBalancerClient loadBalancerClient) {
		return new LoadBalancerRequestFactory(loadBalancerClient, transformers);
	}

5.LoadBalancerInterceptorConfig 负载均衡器的拦截器配置

		// 创建负载均衡拦截器
		@Bean
		public LoadBalancerInterceptor ribbonInterceptor(
				LoadBalancerClient loadBalancerClient,
				LoadBalancerRequestFactory requestFactory) {
			return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
		}
		
		// 构建一个restTemplate定制化器
		// 将拦截器加载到每个restTemplate上去
		@Bean
		@ConditionalOnMissingBean
		public RestTemplateCustomizer restTemplateCustomizer(
				final LoadBalancerInterceptor loadBalancerInterceptor) {
			return restTemplate -> {
                List<ClientHttpRequestInterceptor> list = new ArrayList<>(
                        restTemplate.getInterceptors());
                list.add(loadBalancerInterceptor);
                restTemplate.setInterceptors(list);
            };
		}



4.小结

这篇文章主要为后面几篇做一个铺垫,知道有些东西在哪初始化,配置了哪些东西。看源码,我觉还是不要先死扣细节和那些类的具体作用。先基本了解一下ribbon运行需要哪些前置的东西,然后再去看看ribbon的主流程,最后进行细节深入。

原文链接:https://blog.csdn.net/yang131peng/article/details/117784439



所属网站分类: 技术文章 > 博客

作者:怎么没有鱼儿上钩呢

链接:http://www.javaheidong.com/blog/article/222170/a1f16afef7ee43b3b353/

来源:java黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

9 0
收藏该文
已收藏

评论内容:(最多支持255个字符)