3.1 (配置)默认的配置RibbonClientConfiguration
此配置类也是作为一个默认配置类存在,也就是在你不配置任何东西是SpringCloud-Ribbon
默认装载的核心组件的组合,
相比于Netflix Ribbon
项目DefaultClientConfigImpl
的提供的默认组件为
3.2 (配置)自定义配置
本着可扩展原则: SpringCloudRibbon也要提供个性化配置功能。
3.2.1 注解式配置类
这里涉及两个注解:@RibbonClient
与@RibbonClients
(注意有个s
)
- 这两注解类功能是,被他们注解的类会通过某种机制
RibbonClientConfiguration
替换默认的配置 - 这两个注解的区别是:一个覆盖的是单个服务的某个组件,一个针对多个服务
使用方式如下:我把user
服务负载均衡的IPing
组件替换为我的MyPingUrl
。
Configuration @RibbonClient(name = "user", configuration = UserConfiguration.class) public class UserRibbonConfiguration { } @Configuration protected static class UserConfiguration{ @Bean public IPing ribbonPing() { return new MyPingUrl(); } }
注意 添加UserConfiguration中的配置。UserConfiguration必须使用@Configuration进行声明,而且不能放在可以被main application context的@ComponentScan或@SpringBootApplication扫描到的地方,防止该配置被所有的@RibbonClient共享
如果想把所有服务的负载均衡的的IPing
组件替换为我的MyPingUrl
@RibbonClient(defaultConfiguration = UserConfiguration.class) public class UserRibbonConfiguration { }
工作原理:
这两个注解的工作原理是:通过引入RibbonClientConfigurationRegistrar
注册器,将配置类注册为一个RibbonClientSpecification
@Configuration @Import(RibbonClientConfigurationRegistrar.class)//这里 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface RibbonClient { } //注册器 public class RibbonClientConfigurationRegistrar implements ImportBeanDefinitionRegistrar { private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) { //注册为一个RibbonClientSpecification BeanDefinitionBuilder builder = BeanDefinitionBuilder .genericBeanDefinition(RibbonClientSpecification.class); builder.addConstructorArgValue(name); builder.addConstructorArgValue(configuration); registry.registerBeanDefinition(name + ".RibbonClientSpecification", builder.getBeanDefinition()); } }
RibbonClientSpecification
: 直译为客户端规范,对,你的个性化配置被解析为一个客户端规范
举例说明为:
- A服务,B服务使用同一个个性化配置,A,B服务就有一个
RibbonClientSpecification
规范 - C服务使用一个个性化配置,C服务就有一个
RibbonClientSpecification
规范
这个规范是如何生效的呢?见下文
3.2.1 配置文件里配置:
另一种就是直接在spring体系内的配置文件中配置
application.yml
api-user: ribbon: NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList
在这些属性中定义的类优先于使用@RibbonClient(configuration=MyRibbonConfig.class)定义的bean和由Spring Cloud Netflix提供的默认值。
说了配置,在讲讲使用层面的工作
使用层面的工作:
负载均衡功能的使用其实就在ILoadBalancer
这个统筹组件上。所谓使用,其实就是就在这个ILoadBalancer
上。
3.3 (使用) SpringClientFactory
SpringClientFactory使用工厂模式对外提供:根据serviceId获取IClient, ILoadBalance, ILoadBalanceContext等对象的服务。
这里我们只关注
ILoadBalance
的获取。
SpringClientFactory 为每个服务创建一个独立的上下文,并在其中加载对应的配置及Ribbon核心接口的实现类。创建逻辑在其父类NamedContextFactory
public abstract class NamedContextFactory{ private Map<String, C> configurations = new ConcurrentHashMap<>(); private Class<?> defaultConfigType; //创建上下文 protected AnnotationConfigApplicationContext createContext(String name) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); if (this.configurations.containsKey(name)) { for (Class<?> configuration : this.configurations.get(name) .getConfiguration()) { context.register(configuration); } } for (Map.Entry<String, C> entry : this.configurations.entrySet()) { if (entry.getKey().startsWith("default.")) { for (Class<?> configuration : entry.getValue().getConfiguration()) { context.register(configuration); } } } context.register(PropertyPlaceholderAutoConfiguration.class, this.defaultConfigType); context.getEnvironment().getPropertySources().addFirst(new MapPropertySource( this.propertySourceName, Collections.<String, Object> singletonMap(this.propertyName, name))); if (this.parent != null) { // Uses Environment from parent as well as beans context.setParent(this.parent); } context.refresh(); return context; } }
这里有两个点:
- 根据传入服务
serverId
创建一个AnnotationConfigApplicationContext
,装载属于他自己的负载均衡套件。不同的服务有不同的上下文,里面存储的是属于他的负载均衡套件组合
- 服务的负载均衡套件组合方式。是上文提到的两种配置方式决定的。也就是
configurations
与defaultConfigType
两个属性所代表的规范。
private Map<String, C> configurations = new ConcurrentHashMap<>(); private Class<?> defaultConfigType;//代表默认的组件组合
- configurations :代表的是个性化配置的套件规范。上文提到的
RibbonClientSpecification
- defaultConfigType :代表的就是sc-ribbon的默认配置类
RibbonClientConfiguration
当我们调用SpringClientFactory.getLoadBalancer
方法获取一个负载均衡器实例时, 本质就是在这个服务对应的上下文中取出属于他的ILoadBalancer
实现。