序
本文主要研究一下 spring cloud 的 ConsulServer
ConsulServer
spring-cloud-consul-discovery-2.1.2.RELEASE-sources.jar!/org/springframework/cloud/consul/discovery/ConsulServer.java
public class ConsulServer extends Server {
private final MetaInfo metaInfo;
private final HealthService service;
private final Map<String, String> metadata;
public ConsulServer(final HealthService healthService) {super(findHost(healthService), healthService.getService().getPort());
this.service = healthService;
this.metadata = ConsulServerUtils.getMetadata(this.service);
this.metaInfo = new MetaInfo() {
@Override
public String getAppName() {return ConsulServer.this.service.getService().getService();}
@Override
public String getServerGroup() {return getMetadata().get("group");
}
@Override
public String getServiceIdForDiscovery() {return null;}
@Override
public String getInstanceId() {return ConsulServer.this.service.getService().getId();}
};
setAlive(isPassingChecks());
}
@Override
public MetaInfo getMetaInfo() {return this.metaInfo;}
public HealthService getHealthService() {return this.service;}
public Map<String, String> getMetadata() {return this.metadata;}
public boolean isPassingChecks() {for (Check check : this.service.getChecks()) {if (check.getStatus() != Check.CheckStatus.PASSING) {return false;}
}
return true;
}
}
- ConsulServer 继承了 com.netflix.loadbalancer.Server;其构造器会调用 isPassingChecks 方法来 setAlive,它通过 HealthService 来获取 checks 的状态
ConsulServerList
spring-cloud-consul-discovery-2.1.2.RELEASE-sources.jar!/org/springframework/cloud/consul/discovery/ConsulServerList.java
public class ConsulServerList extends AbstractServerList<ConsulServer> {
private final ConsulClient client;
private final ConsulDiscoveryProperties properties;
private String serviceId;
public ConsulServerList(ConsulClient client, ConsulDiscoveryProperties properties) {
this.client = client;
this.properties = properties;
}
protected ConsulClient getClient() {return this.client;}
protected ConsulDiscoveryProperties getProperties() {return this.properties;}
protected String getServiceId() {return this.serviceId;}
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {this.serviceId = clientConfig.getClientName();
}
@Override
public List<ConsulServer> getInitialListOfServers() {return getServers();
}
@Override
public List<ConsulServer> getUpdatedListOfServers() {return getServers();
}
private List<ConsulServer> getServers() {if (this.client == null) {return Collections.emptyList();
}
String tag = getTag(); // null is ok
Response<List<HealthService>> response = this.client.getHealthServices(this.serviceId, tag, this.properties.isQueryPassing(),
createQueryParamsForClientRequest(), this.properties.getAclToken());
if (response.getValue() == null || response.getValue().isEmpty()) {return Collections.emptyList();
}
return transformResponse(response.getValue());
}
/**
* Transforms the response from Consul in to a list of usable {@link ConsulServer}s.
* @param healthServices the initial list of servers from Consul. Guaranteed to be
* non-empty list
* @return ConsulServer instances
* @see ConsulServer#ConsulServer(HealthService)
*/
protected List<ConsulServer> transformResponse(List<HealthService> healthServices) {List<ConsulServer> servers = new ArrayList<>();
for (HealthService service : healthServices) {ConsulServer server = new ConsulServer(service);
if (server.getMetadata()
.containsKey(this.properties.getDefaultZoneMetadataName())) {server.setZone(server.getMetadata()
.get(this.properties.getDefaultZoneMetadataName()));
}
servers.add(server);
}
return servers;
}
/**
* This method will create the {@link QueryParams} to use when retrieving the services
* from Consul. By default {@link QueryParams#DEFAULT} is used. In case a datacenter
* is specified for the current serviceId {@link QueryParams#datacenter} is set.
* @return an instance of {@link QueryParams}
*/
protected QueryParams createQueryParamsForClientRequest() {String datacenter = getDatacenter();
if (datacenter != null) {return new QueryParams(datacenter);
}
return QueryParams.DEFAULT;
}
protected String getTag() {return this.properties.getQueryTagForService(this.serviceId);
}
protected String getDatacenter() {return this.properties.getDatacenters().get(this.serviceId);
}
@Override
public String toString() {final StringBuilder sb = new StringBuilder("ConsulServerList{");
sb.append("serviceId='").append(this.serviceId).append('\'');
sb.append(", tag=").append(getTag());
sb.append('}');
return sb.toString();}
}
- ConsulServerList 继承了 com.netflix.loadbalancer.AbstractServerList;其 getInitialListOfServers 及 getUpdatedListOfServers 方法都会调用 getServers 方法;它通过 ConsulClient.getHealthServices 来获取指定 serviceId 的 HealthService 列表,然后通过 transformResponse 方法包装为 ConsulServer 列表
ConsulRibbonClientConfiguration
spring-cloud-consul-discovery-2.1.2.RELEASE-sources.jar!/org/springframework/cloud/consul/discovery/ConsulRibbonClientConfiguration.java
@Configuration
public class ConsulRibbonClientConfiguration {
protected static final String VALUE_NOT_SET = "__not__set__";
protected static final String DEFAULT_NAMESPACE = "ribbon";
@Autowired
private ConsulClient client;
@Value("${ribbon.client.name}")
private String serviceId = "client";
public ConsulRibbonClientConfiguration() {}
public ConsulRibbonClientConfiguration(String serviceId) {this.serviceId = serviceId;}
@Bean
@ConditionalOnMissingBean
public ServerList<?> ribbonServerList(IClientConfig config,
ConsulDiscoveryProperties properties) {ConsulServerList serverList = new ConsulServerList(this.client, properties);
serverList.initWithNiwsConfig(config);
return serverList;
}
@Bean
@ConditionalOnMissingBean
public ServerListFilter<Server> ribbonServerListFilter() {return new HealthServiceServerListFilter();
}
@Bean
@ConditionalOnMissingBean
public IPing ribbonPing() {return new ConsulPing();
}
@Bean
@ConditionalOnMissingBean
public ConsulServerIntrospector serverIntrospector() {return new ConsulServerIntrospector();
}
@PostConstruct
public void preprocess() {setProp(this.serviceId, DeploymentContextBasedVipAddresses.key(), this.serviceId);
setProp(this.serviceId, EnableZoneAffinity.key(), "true");
}
protected void setProp(String serviceId, String suffix, String value) {
// how to set the namespace properly?
String key = getKey(serviceId, suffix);
DynamicStringProperty property = getProperty(key);
if (property.get().equals(VALUE_NOT_SET)) {ConfigurationManager.getConfigInstance().setProperty(key, value);
}
}
protected DynamicStringProperty getProperty(String key) {return DynamicPropertyFactory.getInstance().getStringProperty(key, VALUE_NOT_SET);
}
protected String getKey(String serviceId, String suffix) {return serviceId + "." + DEFAULT_NAMESPACE + "." + suffix;}
}
- ConsulRibbonClientConfiguration 注入了 ribbonServerList,其创建的是 ConsulServerList
小结
- ConsulServer 继承了 com.netflix.loadbalancer.Server;其构造器会调用 isPassingChecks 方法来 setAlive,它通过 HealthService 来获取 checks 的状态
- ConsulServerList 继承了 com.netflix.loadbalancer.AbstractServerList;其 getInitialListOfServers 及 getUpdatedListOfServers 方法都会调用 getServers 方法;它通过 ConsulClient.getHealthServices 来获取指定 serviceId 的 HealthService 列表,然后通过 transformResponse 方法包装为 ConsulServer 列表
- ConsulRibbonClientConfiguration 注入了 ribbonServerList,其创建的是 ConsulServerList
doc
- ConsulServer