Spring Cloud LoadBalancer自动配置源码分析

下面笔者结合源码来分析负载均衡器的原理,主要解释它到底是怎样起作用的,以及它都做了什么。

在编码时仅仅添加了 spring-cloud-starter-loadbalancer 依赖和一个 @LoadBalance 注解,负载均衡器就生效了。毋庸置疑,肯定是 Spring Boot 框架的自动装配(Auto Configuration)机制生效了。

本节介绍的 LoadBalancer 自动配置类是 org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration,其源码在 spring-cloud-commons-3.1.1.jar 中,如图 7-6 所示。

有一个与 LoadBalancerAutoConfiguration 同名的类,不过类路径不同,读者要注意区分。

image 2025 04 16 15 10 00 123
Figure 1. 图7-6 LoadBalancerAutoConfiguration 类源码截图

LoadBalancerAutoConfiguration 自动配置类的定义和源码注释如下:

package org.springframework.cloud.client.loadbalancer;

// 配置类
@Configuration(proxyBeanMethods = false)
// 当前项目的 classpath 下存在 RestTemplate 类时生效
@ConditionalOnClass(RestTemplate.class)
// 当前 IoC 容器中存在 LoadBalancerClient 类型的 Bean 时生效
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerClientsProperties.class)
public class LoadBalancerAutoConfiguration {
    省略部分代码

    @Bean // 注册 LoadBalancerRequestFactory 到 IoC 容器中
    @ConditionalOnMissingBean // 当前 IoC 容器中不存在 LoadBalancerRequestFactory类型的 Bean 时注册

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

    @Configuration(proxyBeanMethods = false)
    @Conditional(RetryMissingOrDisabledCondition.class)
    static class LoadBalancerInterceptorConfig {

        @Bean // 注册 LoadBalancerInterceptor 到 IoC 容器中
        public LoadBalancerInterceptor loadBalancerInterceptor(
                LoadBalancerClient loadBalancerClient,
                LoadBalancerRequestFactory requestFactory) {
            return new LoadBalancerInterceptor(loadBalancerClient,
                    requestFactory);
        }
    }

    @Bean // 注册 RestTemplateCustomizer 到 IoC 容器中
    @ConditionalOnMissingBean // 当前 IoC 容器中不存在 RestTemplateCustomizer 类型的 Bean 时注册
    public RestTemplateCustomizer restTemplateCustomizer(final
                                                         LoadBalancerInterceptor loadBalancerInterceptor) {
        return restTemplate -> {
            List<ClientHttpRequestInterceptor> list = new ArrayList<>();
            list.addAll(restTemplate.getInterceptors());
            list.add(loadBalancerInterceptor);
            restTemplate.setInterceptors(list);
        };
    }
}
java

由源码可知,LoadBalancerAutoConfiguration 自动配置类的生效条件有两个。

一个条件是当前项目的 classpath 下存在 RestTemplate 类。由于在 pom.xml 文件中引入了 spring-boot-starter-web 依赖,而 spring-boot-starter-web 依赖中包括 spring-web.jarRestTemplate 类就在 spring-web.jar 中定义,因此该条件会生效。

另一个条件是当前 IoC 容器中存在 LoadBalancerClient 类型的 BeanLoadBalancerClient 是一个接口,其唯一的实现类为 org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient 类。而 BlockingLoadBalancerClient 类也有一个自动配置类 BlockingLoadBalancerClientAutoConfiguration,在 BlockingLoadBalancerClientAutoConfiguration 类定义上有以下明确的代码:

@AutoConfigureBefore({ org.springframework.cloud.client.loadbalancer.
LoadBalancerAutoConfiguration.class,
AsyncLoadBalancerAutoConfiguration.class })
java

也就是说,自动配置类 BlockingLoadBalancerClientAutoConfiguration 一定会在自动配置类 org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration 之前先走完自动配置流程,然后向 IoC 容器中注册 BlockingLoadBalancerClient 类型的 Bean。所以第二个条件也会生效。

继续来看 LoadBalancerAutoConfiguration 自动配置类生效后做了哪些事情。

根据源码可知,在自动配置类生效后,会向 IoC 容器中注册一个 org.springframework.cloud.client.loadbalancer.LoadBalancerRequestFactory 类型的 Bean、一个 org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor 类型的 Bean 和一个 RestTemplateCustomizer 类型的 Bean。其中,RestTemplateCustomizerRestTemplate 类的定制器,也就是说,在该自动配置类生效后,会获取当前 IoC 容器中 RestTemplate 类型的 Bean,并且把一个 LoadBalancerInterceptor 类型的拦截器注入 RestTemplate 类型的 Bean

简单来说,就是 LoadBalancerAutoConfiguration 自动配置类生效后,会在 RestTemplate 工具中做定制化的修改,“塞” 一个拦截器进去。

为了更直观地感受这个过程,打断点后走一遍流程。在自定义的 RestTemplateConfig 类中的第 23 行、LoadBalancerAutoConfiguration 类中的第 89 行和第 98 行分别打一个断点,之后以 Debug 模式启动项目。

在启动过程中,程序直接在 RestTemplateConfig 类中的第 23 行这个断点处停住了,如图 7-7 所示。

此时正在构造一个 RestTemplate 类型的 Bean 并将其注册到 IoC 容器中。注意此时构造的这个 Bean——RestTemplate@4735(这是笔者在分析时的结果,读者在分析时生成的 RestTemplate 内容可能不同)。单击 “Resume Program” 按钮跳过这个断点,程序将分别在 LoadBalancerAutoConfiguration 类中的第 89 行和第 98 行的断点处停住。

如图 7-8 所示,第 98 行的这行代码在执行时会向 IoC 容器中 RestTemplate 类型的 Bean 添加一个拦截器,而此时获取的 RestTemplate 类型的 Bean 就是自定义 RestTemplateConfig 类中构造的那个 Bean——RestTemplate@4735。也就是说,本来 RestTemplate 类好好的,但是 LoadBalancer 集成进来之后,把它给改造了,往里面加了一个拦截器,拦截器中有一个重要的类 BlockingLoadBalancerClient

image 2025 04 16 15 37 31 593
Figure 2. 图7-7 Debug模式下的RestTemplate对象截图
image 2025 04 16 15 37 48 877
Figure 3. 图7-8 LoadBalancerAutoConfiguration 类中对 RestTemplate 实例的处理

以上就是 LoadBalancer 自动配置时的源码分析,主要包括自动配置类的生效条件解释,以及自动配置类生效之后做了哪些事情,读者可以根据分析过程理解和实践。

需要注意,LoadBalancer 自动配置类不止本节中提到的 LoadBalancerAutoConfiguration 这一个。如果未使用 RestTemplate 工具,而使用了 Web FluxWebClient 工具,那么它的自动配置类是另外一个。当前的自动配置类就不会生效了,因篇幅有限,不再拓展,感兴趣的读者可以自行查阅相关资料,其过程和作用是类似的。