加入 spring-cloud-starter-netflix-ribbon
依赖
@Configuration @RibbonClient(name = "foo", configuration = FooConfiguration.class) public class TestConfiguration {}
@Configuration protected static class FooConfiguration { @Bean public ZonePreferenceServerListFilter serverListFilter() { ZonePreferenceServerListFilter filter = new ZonePreferenceServerListFilter(); filter.setZone("myTestZone"); return filter; } @Bean public IPing ribbonPing() { return new PingUrl(); } }
Ribbon客户端的配置, 如果不指定会使用默认的实现:
ConfigurationBasedServerList
和基于Eureka服务发现的
DiscoveryEnabledNIWSServerList
ZoneAffinityServerListFilter
EurekaNotificationServerListUpdater
/拉 PollingServerListUpdater
, 默认是拉) 类结构
实际使用中, 服务调用使用RestTemplate, 请求地址为 http://<serviceName>/<path>
, 如 http://foo/
通过 @RibbonClient
注解为服务创建ribbon客户端, 名字为方法名. RestTemplate发送请求的时候, 请求会被 LoadBalancerInterceptor
拦截到, 使用服务对应的ribbon客户端. Ribbon客户端的 LoadBalancer
会从 ServerList
中根据 IRule
的规则选择某个服务实例作为请求对象. ServerList
有动态的实现, 更新列表时会使用 ServerListFilter
进行过滤.
从注释上 @RibbonClient
为一个ribbon客户端声明配置信息. 把这个注解加在任何 @Configuration
标注的类上, 然后注入 SpringClientFactory
来访问创建的客户端.
从代码上看 @RibbonClient
引入了 RibbonClientConfigurationRegistrar
. RibbonClientConfigurationRegistrar
实现了 ImportBeanDefinitionRegistrar
接口, 在 @Configuration
的解析极端调用接口的 registerBeanDefinitions
方法, 为ribbon客户端创建BeanDefinition
使用 name/value
和 configuration
创建一个 BeanDefinition
. Definition的名为 <name>.RibbonClientSpecification
, class为 RibbonClientSpecification
.
FooConfiguration.class
也要使用 @Configuration
注解, 然后通过 RibbonClientConfigurationRegistrar
关联到Ribbon客户端的BeanDefinition. 所以 不能把FooConfiguration放到@ComponentScan的上下文中, 同样@SpringBootApplication也不行. 必要时使用exclude排除 , 否则会变成所有Ribbon客户端共享.
RibbonAutoConfiguration
中在创建 SpringClientFactory
bean时, 会注入这些 RibbonClientSpecification
. SpringClientFactory
继承了类 NamedContextFactory
. 从注释看 NamedContextFactory
可以创建一组子上下文, 每个子上下文中可以使用一组的Specification来定义bean. 对于Ribbon来说, 每个ribbon客户端各自为一个子上下文, @RibbonClient
的 configuration
指定的配置, 就是用来构建该子上下文的配置, 最终被用来构建ribbon客户端. 这些上下文有共同的父上下文, 即 ApplicationContext
. 这就是为什么上面提到的 FooConfiguration
不能置于 ApplicationContext
中, 否则会被所有的Ribbon客户端共享配置.
通过 RibbonAutoConfiguration
引入, 定义了几个重要的bean:
LoadBalancerRequestFactory
: 1) 将Http请求封装成 ServiceRequestWrapper
. ServiceRequestWrapper
继承并重写了 HttpRquestWrapper
的 getURI
方法: 调用 LoadBalancerClient
的 reconstructURI
方法,创建实际请求的地址. 2) 如果有提供 LoadBalancerRequestTransformer
的实例, 则使用这些实例对相求进行响应的转换.
LoadBalancerInterceptor
: Http请求拦截器, 将请求的 host
作为 serviceName
并使用 LoadBalancerRequestFactory
封装请求, 调用 LoadBalancerClient
的 execute
方法, 发送请求到真实的服务实例地址, 返回响应
RestTemplateCustomizer
: 提供一个 RestTemplateCustomizer
的匿名类实现, 为所有的RestTemplate实例添加一个 LoadBalancerInterceptor
拦截器 通过spring.factories引入, RibbonAutoConfiguration
定义了几个重要的bean:
SpringClientFactory
: 使用 @RibbonClient
注解引入的ribbon客户端的配置, 构建ribbon客户端的子上下文, 初始化ribbon客户端bean. 四个get方法, 分别返回对应 service 的 IClient
, ILoadBalancer
, IClientConfig
, RibbonLoadBalancerContext
实例.
LoadBalancerClient
: 使用Spring Cloud提供的实现 RibbonLoadBalancerClient
. 通过 SpringClientFactory
创建一个 ILoadBalancer
实例, 通过 ILoadBalancer
返回一个 Server
实例. 使用 Server
实例.
SpringClientFactory
获取该服务ribbon客户端子上下文 RibbonLoadBalancerContext
对象, 调用 RibbonLoadBalancerContext
的 reconstructURIWithServer
方法构建最终的请求地址 SpringClientFactory
获取该服务的服务均衡器, 使用负载均衡器的 IRule
返回服务实例. execute(): 执行最终的请求, 并记录状态: ServerStats
和 Stopwatch