聊聊ZookeeperDiscoveryAutoConfiguration

28次阅读

共计 12384 个字符,预计需要花费 31 分钟才能阅读完成。

本文主要研究一下 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

正文完
 0