一般SpringCloud环境下是Ribbon+Eureka一起使用的:
SpringCloud环境下Ribbon+Eureka配置
示例项目
添加依赖:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> </dependency>
添加配置:
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:
@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<EurekaClient> 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的逻辑是一样的,这里不再赘述