本文基于SpringCloud-Dalston.SR5
一般SpringCloud环境下是Ribbon Eureka一起使用的:
SpringCloud环境下Ribbon Eureka配置
示例项目
实例项目地址:https://github.com/HashZhang/ScanfoldAll/tree/master/Scanfold-SpringCloud/Scanfold-SpringCloud-Ribbon/Scanfold-SpringCloud-RibbonWithEureka
添加依赖:
代码语言:javascript复制<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-ribbonartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-eurekaartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.retrygroupId>
<artifactId>spring-retryartifactId>
dependency>
添加配置:
代码语言:javascript复制spring.application.name=Scanfold-SpringCloud-RibbonWithEureka
server.port=8081
######## ribbon ########
#ribbon连接超时
test-service-provider.ribbon.ConnectTimeout=50
#ribbon读超时
test-service-provider.ribbon.ReadTimeout=8000
#最多重试多少台服务器
test-service-provider.ribbon.MaxAutoRetriesNextServer=1
#每台服务器最多重试次数,但是首次调用不包括在内
test-service-provider.ribbon.MaxAutoRetries=1
test-service-provider.ribbon.retryableStatusCodes=500
test-service-provider.ribbon.OkToRetryOnAllOperations=true
#服务过期时间配置,超过这个时间没有接收到心跳EurekaServer就会将这个实例剔除
#注意,EurekaServer一定要设置eureka.server.eviction-interval-timer-in-ms否则这个配置无效,这个配置一般为服务刷新时间配置的三倍
#默认90s
eureka.instance.lease-expiration-duration-in-seconds=15
#服务刷新时间配置,每隔这个时间会主动心跳一次
#默认30s
eureka.instance.lease-renewal-interval-in-seconds=5
#eureka client刷新本地缓存时间
#默认30s
eureka.client.registryFetchIntervalSeconds=5
#eureka客户端ribbon刷新时间
#默认30s
ribbon.ServerListRefreshInterval=1000
eureka.instance.preferIpAddress=true
eureka.client.serviceUrl.defaultZone=http://127.0.0.1:8211/eureka/
源码分析
类似于纯Ribbon的初始化,也是通过Intereceptor初始化Configuration,只不过这次主角是EurekaRibbonClientConfiguration:
代码语言:javascript复制@Bean
@ConditionalOnMissingBean
public IPing ribbonPing(IClientConfig config) {
if (this.propertiesFactory.isSet(IPing.class, this.serviceId)) {
return (IPing)this.propertiesFactory.get(IPing.class, config, this.serviceId);
} else {
NIWSDiscoveryPing ping = new NIWSDiscoveryPing();
ping.initWithNiwsConfig(config);
return ping;
}
}
@Bean
@ConditionalOnMissingBean
public ServerList ribbonServerList(IClientConfig config, Provider eurekaClientProvider) {
if (this.propertiesFactory.isSet(ServerList.class, this.serviceId)) {
return (ServerList)this.propertiesFactory.get(ServerList.class, config, this.serviceId);
} else {
DiscoveryEnabledNIWSServerList discoveryServerList = new DiscoveryEnabledNIWSServerList(config, eurekaClientProvider);
DomainExtractingServerList serverList = new DomainExtractingServerList(discoveryServerList, config, this.approximateZoneFromHostname);
return serverList;
}
}
@Bean
public ServerIntrospector serverIntrospector() {
return new EurekaServerIntrospector();
}
@PostConstruct
public void preprocess() {
String zone = ConfigurationManager.getDeploymentContext().getValue(ContextKey.zone);
if (this.clientConfig != null && StringUtils.isEmpty(zone)) {
String availabilityZone;
if (this.approximateZoneFromHostname && this.eurekaConfig != null) {
availabilityZone = ZoneUtils.extractApproximateZone(this.eurekaConfig.getHostName(false));
log.debug("Setting Zone To " availabilityZone);
ConfigurationManager.getDeploymentContext().setValue(ContextKey.zone, availabilityZone);
} else {
availabilityZone = this.eurekaConfig == null ? null : (String)this.eurekaConfig.getMetadataMap().get("zone");
if (availabilityZone == null) {
String[] zones = this.clientConfig.getAvailabilityZones(this.clientConfig.getRegion());
availabilityZone = zones != null && zones.length > 0 ? zones[0] : null;
}
if (availabilityZone != null) {
ConfigurationManager.getDeploymentContext().setValue(ContextKey.zone, availabilityZone);
}
}
}
RibbonUtils.setRibbonProperty(this.serviceId, CommonClientConfigKey.DeploymentContextBasedVipAddresses.key(), this.serviceId);
RibbonUtils.setRibbonProperty(this.serviceId, CommonClientConfigKey.EnableZoneAffinity.key(), "true");
}
通过源码,可以看出,IPing的默认实现变成了NIWSDiscoveryPing,ServerList的默认实现变成DomainExtractingServerList;
NIWSDiscoveryPing之前的文章里面我们分析过其源码,ServerList的默认实现是基于DiscoveryEnabledNIWSServerList(之前也分析过)外面再包一层DomainExtractingServerList
这个DomainExtractingServerList其实就是在DiscoveryEnabledNIWSServerList返回的Server基础上封装了Zone信息,主要获取和更新逻辑还是DiscoveryEnabledNIWSServerList
至于调用还有重试和之前纯Ribbon的逻辑是一样的,这里不再赘述