Spring Cloud LoadBalancer 如何指定服务使用指定负载均衡策略
当系统中有多个服务A,B,C时 默认使用轮询策略 当我们A服务需要使用指定IP策略时 只需要在spring boot 代码中使用注解
@LoadBalancerClients(value = {@LoadBalancerClient(value = "A")},defaultConfiguration = IpLoadBalancerConfig.class)
就这? 没这么简单
点开@LoadBalancerClients 源码可以看到
@Configuration(proxyBeanMethods = false)
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
@Documented
@Import(LoadBalancerClientConfigurationRegistrar.class)
public @interface LoadBalancerClients {
LoadBalancerClient[] value() default {};
/**
* {@link LoadBalancerClientConfigurationRegistrar} creates a
* {@link LoadBalancerClientSpecification} with this as an argument. These in turn are
* added as default contexts in {@link LoadBalancerClientFactory}. Configuration
* defined in these classes are used as defaults if values aren't defined via
* {@link LoadBalancerClient#configuration()}
* @return classes for default configurations
*/
Class<?>[] defaultConfiguration() default {};
}
LoadBalancerClients 注解上有使用 @Import(LoadBalancerClientConfigurationRegistrar.class) 注解倒入一个配置类 该类实现了ImportBeanDefinitionRegistrar�接口 spring 在加载该类时 会主动调用该接口 registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry)� 用来注册bean
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
Map<String, Object> attrs = metadata.getAnnotationAttributes(LoadBalancerClients.class.getName(), true);
if (attrs != null && attrs.containsKey("value")) {
AnnotationAttributes[] clients = (AnnotationAttributes[]) attrs.get("value");
for (AnnotationAttributes client : clients) {
registerClientConfiguration(registry, getClientName(client), client.get("configuration"));
}
}
if (attrs != null && attrs.containsKey("defaultConfiguration")) {
String name;
if (metadata.hasEnclosingClass()) {
name = "default." + metadata.getEnclosingClassName();
}
else {
name = "default." + metadata.getClassName();
}
registerClientConfiguration(registry, name, attrs.get("defaultConfiguration"));
}
Map<String, Object> client = metadata.getAnnotationAttributes(LoadBalancerClient.class.getName(), true);
String name = getClientName(client);
if (name != null) {
registerClientConfiguration(registry, name, client.get("configuration"));
}
}
查看imput导入的类发现 registerBeanDefinitions 第一个参数返回的是LoadBalancerClients 注解 获取到使用的注解信息时 那么就可以BeanDefinitionRegistry 中 进行注册bean 信息 registerClientConfiguration(registry, name, client.get("configuration"));
private static void registerClientConfiguration(BeanDefinitionRegistry registry, Object name,
Object configuration) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(LoadBalancerClientSpecification.class);
builder.addConstructorArgValue(name);
builder.addConstructorArgValue(configuration);
registry.registerBeanDefinition(name + ".LoadBalancerClientSpecification", builder.getBeanDefinition());
}
BeanDefinitionBuilder构建了一个LoadBalancerClientSpecification的BeanDefinition 并向该类的构造方法中指定了两个参数 服务名称以及 配置类 openfeign初始化时会从LoadBalancerClientSpecification 中获取
如果发现 每次我们发现 修改一个服务的选取策略需要去修改代码 就很麻烦 那么我们是否可以 通过配置文件来修改服务的选取策略 答案是当然可以的
我们只需要增加一个配置类 实现 BeanDefinitionRegistryPostProcessor 与 EnvironmentAware 接口则可以
EnvironmentAware 接口 会返回程序中所有配置信息 nacos,啊菠萝里的也可以 只需要在BeanDefinitionRegistryPostProcessor 的接口方法中解析出配置 构建LoadBalancerClientSpecification的BeanDefinition 就可以了
具体的后续在写

浙公网安备 33010602011771号