序
本文主要研究一下 ZookeeperDiscoveryAutoConfiguration
ZookeeperDiscoveryAutoConfiguration
spring-cloud-zookeeper-discovery-2.1.2.RELEASE-sources.jar!/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryAutoConfiguration.java
@Configuration
@ConditionalOnBean(ZookeeperDiscoveryClientConfiguration.Marker.class)
@ConditionalOnZookeeperDiscoveryEnabled
@AutoConfigureBefore({ CommonsClientAutoConfiguration.class,
NoopDiscoveryClientAutoConfiguration.class })
@AutoConfigureAfter({ZookeeperDiscoveryClientConfiguration.class})
public class ZookeeperDiscoveryAutoConfiguration {@Autowired(required = false)
private ZookeeperDependencies zookeeperDependencies;
@Autowired
private CuratorFramework curator;
@Bean
@ConditionalOnMissingBean
public ZookeeperDiscoveryProperties zookeeperDiscoveryProperties(InetUtils inetUtils) {return new ZookeeperDiscoveryProperties(inetUtils);
}
@Bean
@ConditionalOnMissingBean
// currently means auto-registration is false. That will change when
// ZookeeperServiceDiscovery is gone
public ZookeeperDiscoveryClient zookeeperDiscoveryClient(
ServiceDiscovery<ZookeeperInstance> serviceDiscovery,
ZookeeperDiscoveryProperties zookeeperDiscoveryProperties) {
return new ZookeeperDiscoveryClient(serviceDiscovery, this.zookeeperDependencies,
zookeeperDiscoveryProperties);
}
@Bean
public ZookeeperServiceWatch zookeeperServiceWatch(ZookeeperDiscoveryProperties zookeeperDiscoveryProperties) {return new ZookeeperServiceWatch(this.curator, zookeeperDiscoveryProperties);
}
@Configuration
@ConditionalOnEnabledHealthIndicator("zookeeper")
@ConditionalOnClass(Endpoint.class)
protected static class ZookeeperDiscoveryHealthConfig {@Autowired(required = false)
private ZookeeperDependencies zookeeperDependencies;
@Bean
@ConditionalOnMissingBean
public ZookeeperDiscoveryHealthIndicator zookeeperDiscoveryHealthIndicator(
CuratorFramework curatorFramework,
ServiceDiscovery<ZookeeperInstance> serviceDiscovery,
ZookeeperDiscoveryProperties properties) {
return new ZookeeperDiscoveryHealthIndicator(curatorFramework,
serviceDiscovery, this.zookeeperDependencies, properties);
}
}
}
- ZookeeperDiscoveryAutoConfiguration 注册了 ZookeeperDiscoveryProperties、ZookeeperDiscoveryClient、ZookeeperServiceWatch、ZookeeperDiscoveryHealthIndicator
ZookeeperDiscoveryProperties
spring-cloud-zookeeper-discovery-2.1.2.RELEASE-sources.jar!/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryProperties.java
@ConfigurationProperties("spring.cloud.zookeeper.discovery")
public class ZookeeperDiscoveryProperties {
/**
* Default URI spec.
*/
public static final String DEFAULT_URI_SPEC = "{scheme}://{address}:{port}";
private InetUtils.HostInfo hostInfo;
private boolean enabled = true;
/**
* Root Zookeeper folder in which all instances are registered.
*/
private String root = "/services";
/**
* The URI specification to resolve during service registration in Zookeeper.
*/
private String uriSpec = DEFAULT_URI_SPEC;
/** Id used to register with zookeeper. Defaults to a random UUID. */
private String instanceId;
/**
* Predefined host with which a service can register itself in Zookeeper. Corresponds
* to the {code address} from the URI spec.
*/
private String instanceHost;
/**
* IP address to use when accessing service (must also set preferIpAddress to use).
*/
private String instanceIpAddress;
/**
* Use ip address rather than hostname during registration.
*/
private boolean preferIpAddress = false;
/** Port to register the service under (defaults to listening port). */
private Integer instancePort;
/** Ssl port of the registered service. */
private Integer instanceSslPort;
/**
* Register as a service in zookeeper.
*/
private boolean register = true;
/**
* Gets the metadata name/value pairs associated with this instance. This information
* is sent to zookeeper and can be used by other instances.
*/
private Map<String, String> metadata = new HashMap<>();
/**
* The initial status of this instance (defaults to
* {@link StatusConstants#STATUS_UP}).
*/
private String initialStatus = StatusConstants.STATUS_UP;
/**
* Order of the discovery client used by `CompositeDiscoveryClient` for sorting
* available clients.
*/
private int order = 0;
//......
}
- ZookeeperDiscoveryProperties 定义了 enabled、root、uriSpec、instanceId、instanceHost、instanceIpAddress、preferIpAddress、instancePort、instanceSslPort、register、metadata、initialStatus、order 属性
ZookeeperDiscoveryClient
spring-cloud-zookeeper-discovery-2.1.2.RELEASE-sources.jar!/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryClient.java
public class ZookeeperDiscoveryClient implements DiscoveryClient {private static final Log log = LogFactory.getLog(ZookeeperDiscoveryClient.class);
private final ZookeeperDependencies zookeeperDependencies;
private final ServiceDiscovery<ZookeeperInstance> serviceDiscovery;
private final ZookeeperDiscoveryProperties zookeeperDiscoveryProperties;
public ZookeeperDiscoveryClient(ServiceDiscovery<ZookeeperInstance> serviceDiscovery,
ZookeeperDependencies zookeeperDependencies,
ZookeeperDiscoveryProperties zookeeperDiscoveryProperties) {
this.serviceDiscovery = serviceDiscovery;
this.zookeeperDependencies = zookeeperDependencies;
this.zookeeperDiscoveryProperties = zookeeperDiscoveryProperties;
}
@Override
public String description() {return "Spring Cloud Zookeeper Discovery Client";}
private static org.springframework.cloud.client.ServiceInstance createServiceInstance(String serviceId, ServiceInstance<ZookeeperInstance> serviceInstance) {return new ZookeeperServiceInstance(serviceId, serviceInstance);
}
@Override
public List<org.springframework.cloud.client.ServiceInstance> getInstances(final String serviceId) {
try {if (getServiceDiscovery() == null) {return Collections.EMPTY_LIST;}
String serviceIdToQuery = getServiceIdToQuery(serviceId);
Collection<ServiceInstance<ZookeeperInstance>> zkInstances = getServiceDiscovery()
.queryForInstances(serviceIdToQuery);
List<org.springframework.cloud.client.ServiceInstance> instances = new ArrayList<>();
for (ServiceInstance<ZookeeperInstance> instance : zkInstances) {instances.add(createServiceInstance(serviceIdToQuery, instance));
}
return instances;
}
catch (KeeperException.NoNodeException e) {if (log.isDebugEnabled()) {
log.debug(
"Error getting instances from zookeeper. Possibly, no service has registered.",
e);
}
// this means that nothing has registered as a service yes
return Collections.emptyList();}
catch (Exception exception) {rethrowRuntimeException(exception);
}
return new ArrayList<>();}
private ServiceDiscovery<ZookeeperInstance> getServiceDiscovery() {return this.serviceDiscovery;}
private String getServiceIdToQuery(String serviceId) {
if (this.zookeeperDependencies != null
&& this.zookeeperDependencies.hasDependencies()) {String pathForAlias = this.zookeeperDependencies.getPathForAlias(serviceId);
return pathForAlias.isEmpty() ? serviceId : pathForAlias;}
return serviceId;
}
@Override
public List<String> getServices() {
List<String> services = null;
if (getServiceDiscovery() == null) {
log.warn("Service Discovery is not yet ready - returning empty list of services");
return Collections.emptyList();}
try {Collection<String> names = getServiceDiscovery().queryForNames();
if (names == null) {return Collections.emptyList();
}
services = new ArrayList<>(names);
}
catch (KeeperException.NoNodeException e) {if (log.isDebugEnabled()) {
log.debug(
"Error getting services from zookeeper. Possibly, no service has registered.",
e);
}
// this means that nothing has registered as a service yes
return Collections.emptyList();}
catch (Exception e) {rethrowRuntimeException(e);
}
return services;
}
@Override
public int getOrder() {return this.zookeeperDiscoveryProperties.getOrder();
}
}
- ZookeeperDiscoveryClient 实现了 org.springframework.cloud.client.discovery.DiscoveryClient 接口,其 getInstances 使用 curator 的 ServiceDiscovery.queryForInstances 获取服务实例信息,然后转换为 org.springframework.cloud.client.ServiceInstance 类型;getServices 则是使用 curator 的 ServiceDiscovery.queryForNames 获取服务名信息
ZookeeperServiceWatch
spring-cloud-zookeeper-discovery-2.1.2.RELEASE-sources.jar!/org/springframework/cloud/zookeeper/discovery/ZookeeperServiceWatch.java
public class ZookeeperServiceWatch
implements ApplicationListener<InstanceRegisteredEvent<?>>, TreeCacheListener,
ApplicationEventPublisherAware {
private final CuratorFramework curator;
private final ZookeeperDiscoveryProperties properties;
private final AtomicLong cacheChange = new AtomicLong(0);
private ApplicationEventPublisher publisher;
private TreeCache cache;
public ZookeeperServiceWatch(CuratorFramework curator,
ZookeeperDiscoveryProperties properties) {
this.curator = curator;
this.properties = properties;
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {this.publisher = publisher;}
public TreeCache getCache() {return this.cache;}
@Override
public void onApplicationEvent(InstanceRegisteredEvent<?> event) {this.cache = TreeCache.newBuilder(this.curator, this.properties.getRoot())
.build();
this.cache.getListenable().addListener(this);
try {this.cache.start();
}
catch (Exception e) {ReflectionUtils.rethrowRuntimeException(e);
}
}
@PreDestroy
public void stop() throws Exception {if (this.cache != null) {this.cache.close();
}
}
@Override
public void childEvent(CuratorFramework client, TreeCacheEvent event)
throws Exception {if (event.getType().equals(TreeCacheEvent.Type.NODE_ADDED)
|| event.getType().equals(TreeCacheEvent.Type.NODE_REMOVED)
|| event.getType().equals(TreeCacheEvent.Type.NODE_UPDATED)) {long newCacheChange = this.cacheChange.incrementAndGet();
this.publisher.publishEvent(new HeartbeatEvent(this, newCacheChange));
}
}
}
- ZookeeperServiceWatch 实现了 ApplicationListener、TreeCacheListener、ApplicationEventPublisherAware 接口;其 childEvent 方法在 event 类型是 NODE_ADDED、NODE_REMOVED、NODE_UPDATED 类型时会发布 HeartbeatEvent 事件
ZookeeperDiscoveryHealthIndicator
spring-cloud-zookeeper-discovery-2.1.2.RELEASE-sources.jar!/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryHealthIndicator.java
public class ZookeeperDiscoveryHealthIndicator implements DiscoveryHealthIndicator {
private static final Log log = LogFactory
.getLog(ZookeeperDiscoveryHealthIndicator.class);
private CuratorFramework curatorFramework;
private ServiceDiscovery<ZookeeperInstance> serviceDiscovery;
private final ZookeeperDependencies zookeeperDependencies;
private final ZookeeperDiscoveryProperties zookeeperDiscoveryProperties;
public ZookeeperDiscoveryHealthIndicator(CuratorFramework curatorFramework,
ServiceDiscovery<ZookeeperInstance> serviceDiscovery,
ZookeeperDependencies zookeeperDependencies,
ZookeeperDiscoveryProperties zookeeperDiscoveryProperties) {
this.curatorFramework = curatorFramework;
this.serviceDiscovery = serviceDiscovery;
this.zookeeperDependencies = zookeeperDependencies;
this.zookeeperDiscoveryProperties = zookeeperDiscoveryProperties;
}
@Override
public String getName() {return "zookeeper";}
@Override
public Health health() {Health.Builder builder = Health.unknown();
try {
Iterable<ServiceInstance<ZookeeperInstance>> allInstances = new ZookeeperServiceInstances(
this.curatorFramework, this.serviceDiscovery,
this.zookeeperDependencies, this.zookeeperDiscoveryProperties);
builder.up().withDetail("services", allInstances);
}
catch (Exception e) {log.error("Error", e);
builder.down(e);
}
return builder.build();}
}
- ZookeeperDiscoveryHealthIndicator 实现了 DiscoveryHealthIndicator 接口,其 health 方法创建 ZookeeperServiceInstances
ZookeeperServiceInstances
spring-cloud-zookeeper-discovery-2.1.2.RELEASE-sources.jar!/org/springframework/cloud/zookeeper/discovery/ZookeeperServiceInstances.java
public class ZookeeperServiceInstances
implements Iterable<ServiceInstance<ZookeeperInstance>> {private static final Log log = LogFactory.getLog(ZookeeperServiceInstances.class);
private ServiceDiscovery<ZookeeperInstance> serviceDiscovery;
private final ZookeeperDependencies zookeeperDependencies;
private final ZookeeperDiscoveryProperties zookeeperDiscoveryProperties;
private final List<ServiceInstance<ZookeeperInstance>> allInstances;
private final CuratorFramework curator;
public ZookeeperServiceInstances(CuratorFramework curator,
ServiceDiscovery<ZookeeperInstance> serviceDiscovery,
ZookeeperDependencies zookeeperDependencies,
ZookeeperDiscoveryProperties zookeeperDiscoveryProperties) {
this.curator = curator;
this.serviceDiscovery = serviceDiscovery;
this.zookeeperDependencies = zookeeperDependencies;
this.zookeeperDiscoveryProperties = zookeeperDiscoveryProperties;
this.allInstances = getZookeeperInstances();}
private List<ServiceInstance<ZookeeperInstance>> getZookeeperInstances() {ArrayList<ServiceInstance<ZookeeperInstance>> allInstances = new ArrayList<>();
try {Collection<String> namesToQuery = getNamesToQuery();
if (log.isDebugEnabled()) {log.debug("Querying the following names [" + namesToQuery + "]");
}
for (String name : namesToQuery) {allInstances.addAll(nestedInstances(allInstances, name));
}
return allInstances;
}
catch (Exception e) {
log.debug("Exception occurred while trying to build the list of instances",
e);
return allInstances;
}
}
//......
}
- ZookeeperServiceInstances 的构造器会调用 getZookeeperInstances 拉取 ServiceInstance
小结
ZookeeperDiscoveryAutoConfiguration 注册了 ZookeeperDiscoveryProperties、ZookeeperDiscoveryClient、ZookeeperServiceWatch、ZookeeperDiscoveryHealthIndicator
doc
- ZookeeperDiscoveryAutoConfiguration