前几篇文章我们分析了Ribbon的简单使用,和执行流程以及配置原理等等,还记得我们集成RestTemplate时使用了@LoadBalanced注解

  1. // 带负载均衡的http客户端
  2. @LoadBalanced
  3. @Bean
  4. public RestTemplate restTemplate(RestTemplateBuilder builder) {
  5. return builder.build();
  6. }
  7. @Autowired
  8. private RestTemplate restTemplate;
  9. @GetMapping("/allOrders/2")
  10. public Object getOrders() {
  11. return restTemplate.getForObject("http://order-service/orders", String.class);
  12. }

我们看看加了@LoadBalanced注解生成的Bean有哪些不同
image.png
我们发现这个注解的作用是给RestTemplate的Bean增加了一个拦截器LoadBalancerInterceptor
其如何插入拦截器的呢?我们先看看这个注解定义

@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
// 就仅仅是元标注了@Qualifier
@Qualifier
public @interface LoadBalanced {
}

依据我们学习Spring的知识,我们知道这个@Qualifier注解是用于给Bean分组或tag标记的,这里我们可以大胆猜测一定有一个RestTemplate自动注入的地方。

package org.springframework.cloud.client.loadbalancer;

@Configuration
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {
    // 分组标签注入
    @LoadBalanced
    @Autowired(required = false)
    private List<RestTemplate> restTemplates = Collections.emptyList();

    @Autowired(required = false)
    private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();

    // 创建LoadBalancerRequestFactory Bean
    @Bean
    @ConditionalOnMissingBean
    public LoadBalancerRequestFactory loadBalancerRequestFactory(
            LoadBalancerClient loadBalancerClient) {
        return new LoadBalancerRequestFactory(loadBalancerClient, transformers);
    }

    @Configuration
    @ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
    static class LoadBalancerInterceptorConfig {
        // 配置拦截器Bean  LoadBalancerInterceptor
        @Bean
        public LoadBalancerInterceptor ribbonInterceptor(
                LoadBalancerClient loadBalancerClient,
                LoadBalancerRequestFactory requestFactory) {
            return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
        }
        // 扩展Bean RestTemplateCustomizer
        @Bean
        @ConditionalOnMissingBean
        public RestTemplateCustomizer restTemplateCustomizer(
                final LoadBalancerInterceptor loadBalancerInterceptor) {
            return new RestTemplateCustomizer() {
                @Override
                public void customize(RestTemplate restTemplate) {
                    List<ClientHttpRequestInterceptor> list = new ArrayList<>(restTemplate.getInterceptors());
                    // 将LoadBalancerInterceptor拦截器Bean追加到RestTemplate中
                    list.add(loadBalancerInterceptor);
                    restTemplate.setInterceptors(list);
                }
            };
        }

    }

    // 新建一个匿名生命周期Bean,初试化后调用afterSingletonsInstantiated,执行插件的插入逻辑
    @Bean
    public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
            final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
        return new SmartInitializingSingleton() {
            @Override
            public void afterSingletonsInstantiated() {
                restTemplateCustomizers.ifAvailable(new Consumer<List<RestTemplateCustomizer>>() {
                    @Override
                    public void accept(List<RestTemplateCustomizer> customizers) {
                        for (RestTemplate restTemplate : restTemplates) {
                            for (RestTemplateCustomizer customizer : customizers) {
                                customizer.customize(restTemplate);
                            }
                        }
                    }
                });
            }
        };
    }
}

至此,生成的RestTemplate对象就有了LoadBalancerInterceptor插件,我们看看这个插件如何介入负载均衡流程。

LoadBalancerInterceptor

public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {

    private LoadBalancerClient loadBalancer;
    private LoadBalancerRequestFactory requestFactory;

    public LoadBalancerInterceptor(LoadBalancerClient loadBalancer, LoadBalancerRequestFactory requestFactory) {
        this.loadBalancer = loadBalancer;
        this.requestFactory = requestFactory;
    }

    @Override
    public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
            final ClientHttpRequestExecution execution) throws IOException {
        String serviceName = originalUri.getHost();
        // 执行到LoadBalancerClient客户端
        return this.loadBalancer.execute(serviceName, requestFactory.createRequest(request, body, execution));
    }
}

前面我们已经分析过LoadBalancerClient,这里我们直接看执行方法

// RibbonLoadBalancerClient
@Override
public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
    // 获取负载均衡器,选择合适的服务节点
    ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
    Server server = getServer(loadBalancer);
    if (server == null) {
        throw new IllegalStateException("No instances available for " + serviceId);
    }
    // 
    RibbonServer ribbonServer = new RibbonServer(serviceId, server, isSecure(server,
            serviceId), serverIntrospector(serviceId).getMetadata(server));
    // 选择好节点后,最终执行
    return execute(serviceId, ribbonServer, request);
}

// 根据选择好的服务节点执行请求逻辑,回到RestTemplate执行
@Override
public <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException {
    Server server = null;
    if(serviceInstance instanceof RibbonServer) {
        server = ((RibbonServer)serviceInstance).getServer();
    }
    if (server == null) {
        throw new IllegalStateException("No instances available for " + serviceId);
    }

    RibbonLoadBalancerContext context = this.clientFactory
            .getLoadBalancerContext(serviceId);
    // 统计信息
    RibbonStatsRecorder statsRecorder = new RibbonStatsRecorder(context, server);

    try {
        // 执行原始请求
        T returnVal = request.apply(serviceInstance);
        // 统计信息
        statsRecorder.recordStats(returnVal);
        return returnVal;
    } catch (Exception ex) {
        statsRecorder.recordStats(ex);
        ReflectionUtils.rethrowRuntimeException(ex);
    }
    return null;
}

总结:
从这里我们可以看出,Ribbon就是通过插件的方式介入了RestTemplate的执行流程,在插件中根据host名称,将名称替换为负载均衡选择出来的服务节点的ip和端口,替换掉原URL中的host发起真正的请求。