简略示例
Ribbon的应用在Eureka - 简略示例曾经提过了一下,咱们能够把provider复制一份进去,批改端口并注册到注册核心,如下图所示(代码跟之前的雷同,就不贴了):
外围调用代码:
ResponseEntity<String> forEntity = restTemplate.getForEntity("http://eureka-provider/getInfo?name=" + name, String.class);@Bean@LoadBalancedpublic RestTemplate restTemplate() { return new RestTemplate();}
在url里并没有写ip和端口,而是利用名称。拜访Consumer的地址,能够看到轮询的拜访两个Provider。
源码剖析
@RibbonClients
还是从spring.factories说起,在Eureka Client和Ribbon的spring.factories有以下内容:
// Ribbonorg.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration// Eureka Clientorg.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration
这两个类都有@RibbonClients
注解,外面import了RibbonClientConfigurationRegistrar类。
@Configuration(proxyBeanMethods = false)@Retention(RetentionPolicy.RUNTIME)@Target({ ElementType.TYPE })@Documented@Import(RibbonClientConfigurationRegistrar.class)public @interface RibbonClients { RibbonClient[] value() default {}; Class<?>[] defaultConfiguration() default {};}
RibbonClientConfigurationRegistrar实现了ImportBeanDefinitionRegistrar接口,这个接口是用来动静的创立bean,registerBeanDefinitions办法里,会解决应用@RibbonClients
和 @RibbonClient
注解的类,并调用上面的registerClientConfiguration办法。因为下面两个类应用了@RibbonClients
注解,所以会创立两个RibbonClientSpecification类型的bean,名字别离为default.org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration
和default.org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration
。
// 其余代码略private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) { BeanDefinitionBuilder builder = BeanDefinitionBuilder .genericBeanDefinition(RibbonClientSpecification.class); builder.addConstructorArgValue(name); builder.addConstructorArgValue(configuration); registry.registerBeanDefinition(name + ".RibbonClientSpecification", builder.getBeanDefinition());}
SpringClientFactory
SpringClientFactory是创立RibbonClient负载平衡的工厂类,他会创立一个独立的ApplicationContext以及RibbonClient相干的bean,这个前面会持续解说这个内容。在SpringClientFactory实例化的时候,会赋值configurations,这个configurations就是下面的RibbonClientSpecification。SpringClientFactory实例化的适宜,在构造函数会传RibbonClientConfiguration.class,这个前面解说作用。
@Bean@ConditionalOnMissingBeanpublic SpringClientFactory springClientFactory() { SpringClientFactory factory = new SpringClientFactory(); factory.setConfigurations(this.configurations); return factory;}
LoadBalancerClient
客户端负载均衡器,这里注入的下面的SpringClientFactory。
@Bean@ConditionalOnMissingBean(LoadBalancerClient.class)public LoadBalancerClient loadBalancerClient() { return new RibbonLoadBalancerClient(springClientFactory());}
LoadBalancerRequestFactory
这里注入的下面的LoadBalancerClient。
@Bean@ConditionalOnMissingBeanpublic LoadBalancerRequestFactory loadBalancerRequestFactory( LoadBalancerClient loadBalancerClient) { return new LoadBalancerRequestFactory(loadBalancerClient, this.transformers);}
LoadBalancerInterceptor
次要是用于客户端申请的拦挡,通过拦挡实现负载平衡。这里注入的是LoadBalancerClient和LoadBalancerRequestFactory。
@Beanpublic LoadBalancerInterceptor loadBalancerInterceptor( LoadBalancerClient loadBalancerClient, LoadBalancerRequestFactory requestFactory) { return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);}
RestTemplateCustomizer
restTemplate.setInterceptors(list),是给restTemplate减少LoadBalancerInterceptor,这个LoadBalancerInterceptor是下面注入的。
@Bean@ConditionalOnMissingBeanpublic RestTemplateCustomizer restTemplateCustomizer( final LoadBalancerInterceptor loadBalancerInterceptor) { return restTemplate -> { List<ClientHttpRequestInterceptor> list = new ArrayList<>( restTemplate.getInterceptors()); list.add(loadBalancerInterceptor); restTemplate.setInterceptors(list); };}
loadBalancedRestTemplateInitializerDeprecated
先看看LoadBalanced注解,这里引入的是@Qualifier
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@Qualifierpublic @interface LoadBalanced {}
在LoadBalancerAutoConfiguration
类中,有这一行代码,他也引入了@LoadBalanced
,咱们之前Eureka - 简略示例,RestTemplate实例化的时候也是加@LoadBalanced
注解的。他这个意思是只有加了@LoadBalanced
注解的,都注入到restTemplates,所以咱们如果没有在RestTemplate,就没方法注入到这里,也就没方法后续的拦截器注入。
@LoadBalanced@Autowired(required = false)private List<RestTemplate> restTemplates = Collections.emptyList();
在loadBalancedRestTemplateInitializerDeprecated中,因为是SmartInitializingSingleton类型的,所以会调用afterSingletonsInstantiated
办法,return的局部就是这个办法。在这个办法中,会遍历下面@LoadBalanced
的restTemplate,而后再一个个调用RestTemplateCustomizer的办法,实现拦截器注入。
@Beanpublic SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated( final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) { return () -> restTemplateCustomizers.ifAvailable(customizers -> { for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) { for (RestTemplateCustomizer customizer : customizers) { customizer.customize(restTemplate); } } });}