Ribbon的使用在Eureka - 簡單示例已經提過了一下,咱們能夠把provider複製一份出來,修改端口並註冊到註冊中心,以下圖所示(代碼跟以前的雷同,就不貼了):
核心調用代碼:spring
ResponseEntity<String> forEntity = restTemplate.getForEntity("http://eureka-provider/getInfo?name=" + name, String.class); @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); }
在url裏並無寫ip和端口,而是應用名稱。訪問Consumer的地址,能夠看到輪詢的訪問兩個Provider。segmentfault
仍是從spring.factories提及,在Eureka Client和Ribbon的spring.factories有如下內容:負載均衡
// Ribbon org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration // Eureka Client org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration
這兩個類都有@RibbonClients
註解,裏面import了RibbonClientConfigurationRegistrar類。ide
@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是建立RibbonClient負載均衡的工廠類,他會建立一個獨立的ApplicationContext以及RibbonClient相關的bean,這個後面會繼續講解這個內容。在SpringClientFactory實例化的時候,會賦值configurations,這個configurations就是上面的RibbonClientSpecification。SpringClientFactory實例化的適合,在構造函數會傳RibbonClientConfiguration.class,這個後面講解做用。源碼分析
@Bean @ConditionalOnMissingBean public SpringClientFactory springClientFactory() { SpringClientFactory factory = new SpringClientFactory(); factory.setConfigurations(this.configurations); return factory; }
客戶端負載均衡器,這裏注入的上面的SpringClientFactory。ui
@Bean @ConditionalOnMissingBean(LoadBalancerClient.class) public LoadBalancerClient loadBalancerClient() { return new RibbonLoadBalancerClient(springClientFactory()); }
這裏注入的上面的LoadBalancerClient。this
@Bean @ConditionalOnMissingBean public LoadBalancerRequestFactory loadBalancerRequestFactory( LoadBalancerClient loadBalancerClient) { return new LoadBalancerRequestFactory(loadBalancerClient, this.transformers); }
主要是用於客戶端請求的攔截,經過攔截實現負載均衡。這裏注入的是LoadBalancerClient和LoadBalancerRequestFactory。url
@Bean public LoadBalancerInterceptor loadBalancerInterceptor( LoadBalancerClient loadBalancerClient, LoadBalancerRequestFactory requestFactory) { return new LoadBalancerInterceptor(loadBalancerClient, requestFactory); }
restTemplate.setInterceptors(list),是給restTemplate增長LoadBalancerInterceptor,這個LoadBalancerInterceptor是上面注入的。spa
@Bean @ConditionalOnMissingBean public RestTemplateCustomizer restTemplateCustomizer( final LoadBalancerInterceptor loadBalancerInterceptor) { return restTemplate -> { List<ClientHttpRequestInterceptor> list = new ArrayList<>( restTemplate.getInterceptors()); list.add(loadBalancerInterceptor); restTemplate.setInterceptors(list); }; }
先看看LoadBalanced註解,這裏引入的是@Qualifier
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Qualifier public @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的方法,實現攔截器注入。
@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); } } }); }