Ribbon - 初始化

簡單示例

Ribbon的使用在Eureka - 簡單示例已經提過了一下,咱們能夠把provider複製一份出來,修改端口並註冊到註冊中心,以下圖所示(代碼跟以前的雷同,就不貼了):
image.png
核心調用代碼: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

源碼分析

@RibbonClients

仍是從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.RibbonAutoConfigurationdefault.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
@ConditionalOnMissingBean
public SpringClientFactory springClientFactory() {
    SpringClientFactory factory = new SpringClientFactory();
    factory.setConfigurations(this.configurations);
    return factory;
}

LoadBalancerClient

客戶端負載均衡器,這裏注入的上面的SpringClientFactory。ui

@Bean
@ConditionalOnMissingBean(LoadBalancerClient.class)
public LoadBalancerClient loadBalancerClient() {
    return new RibbonLoadBalancerClient(springClientFactory());
}

LoadBalancerRequestFactory

這裏注入的上面的LoadBalancerClient。this

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

LoadBalancerInterceptor

主要是用於客戶端請求的攔截,經過攔截實現負載均衡。這裏注入的是LoadBalancerClient和LoadBalancerRequestFactory。url

@Bean
public LoadBalancerInterceptor loadBalancerInterceptor(
        LoadBalancerClient loadBalancerClient,
        LoadBalancerRequestFactory requestFactory) {
    return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}

RestTemplateCustomizer

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);
    };
}

loadBalancedRestTemplateInitializerDeprecated

先看看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);
            }
        }
    });
}

總結

image.png

相關文章
相關標籤/搜索