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 就可以了

具体的后续在写

posted @ 2022-11-22 22:48  yangqifang  阅读(662)  评论(0)    收藏  举报