@Bean(destroyMethod = "close")
  @ConditionalOnMissingBean
  @SneakyThrows
  public CuratorFramework curatorFramework(
      RetryPolicy retryPolicy, ZookeeperDiscoveryProperties properties) {
    CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder();
    if (ensembleProvider != null) {
      builder.ensembleProvider(ensembleProvider);
    }
    CuratorFramework curator =
        builder
            .retryPolicy(retryPolicy)
            .connectString(zookeeperProperties.getConnectString())
            .build();
    curator.start();

    log.trace(
        "blocking until connected to zookeeper for "
            + properties.getBlockUntilConnectedWait()
            + properties.getBlockUntilConnectedUnit());
    curator.blockUntilConnected(
        properties.getBlockUntilConnectedWait(), properties.getBlockUntilConnectedUnit());
    log.trace("connected to zookeeper");
    return curator;
  }
 @Bean
 @ConditionalOnMissingBean
 public RetryPolicy exponentialBackoffRetry() {
   return new ExponentialBackoffRetry(
       zookeeperProperties.getBaseSleepTimeMs(),
       zookeeperProperties.getMaxRetries(),
       zookeeperProperties.getMaxSleepMs());
 }
 @Bean
 @SneakyThrows
 public ServiceDiscovery<ZookeeperInstance> serviceDiscovery(
     CuratorFramework curatorFramework,
     InstanceSerializer<ZookeeperInstance> instanceSerializer,
     ZookeeperDiscoveryProperties zookeeperProperties) {
   ServiceDiscovery<ZookeeperInstance> serviceDiscovery =
       ServiceDiscoveryBuilder.builder(ZookeeperInstance.class)
           .client(curatorFramework)
           .basePath(zookeeperProperties.getRoot())
           .serializer(instanceSerializer)
           .build();
   serviceDiscovery.start();
   return serviceDiscovery;
 }