# [Spring Cloud Zookeeper](#_spring_cloud_zookeeper)

该项目通过自动配置和绑定到 Spring 环境和其他 Spring 编程模型习惯用法，为 Spring 引导应用程序提供 ZooKeeper 集成。通过一些注释，你可以快速启用和配置应用程序中的常见模式，并使用基于 ZooKeeper 的组件构建大型分布式系统。所提供的模式包括服务发现和配置。该项目还通过集成 Spring Cloud LoadBalancer 提供客户端负载平衡。

## 1.快速启动

这个快速的开始将使用 Spring Cloud ZooKeeper 进行服务发现和分布式配置。

首先，在你的机器上运行 ZooKeeper。然后，你可以访问它，并将其作为服务注册表和配置源使用 Spring Cloud ZooKeeper。

### 1.1.发现客户端使用情况

要在应用程序中使用这些特性，你可以将其构建为依赖于`spring-cloud-zookeeper-core`和`spring-cloud-zookeeper-discovery`的 Spring 引导应用程序。添加依赖项最方便的方法是使用 Spring 引导启动器：`org.springframework.cloud:spring-cloud-starter-zookeeper-discovery`。我们建议使用依赖管理和`spring-boot-starter-parent`。下面的示例展示了一个典型的 Maven 配置：

POM.xml

```
<project>
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>{spring-boot-version}</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>

  <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>${spring-cloud.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
</project>
```

下面的示例显示了一个典型的 Gradle 设置：

构建。 Gradle

```
plugins {
  id 'org.springframework.boot' version ${spring-boot-version}
  id 'io.spring.dependency-management' version ${spring-dependency-management-version}
  id 'java'
}

repositories {
  mavenCentral()
}

dependencies {
  implementation 'org.springframework.cloud:spring-cloud-starter-zookeeper-discovery'
  testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
dependencyManagement {
  imports {
    mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
  }
}
```

|   |根据你使用的版本，你可能需要调整你的项目中使用的 Apache ZooKeeper 版本。<br/>你可以在[安装动物园管理员部分](#spring-cloud-zookeeper-install)中阅读有关它的更多信息。|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

现在，你可以创建一个标准的 Spring 启动应用程序，例如下面的 HTTP 服务器：

```
@SpringBootApplication
@RestController
public class Application {

    @GetMapping("/")
    public String home() {
        return "Hello World!";
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}
```

当这个 HTTP 服务器运行时，它会连接到 ZooKeeper，它在默认的本地端口（2181）上运行。要修改启动行为，可以使用`应用程序.属性`更改 ZooKeeper 的位置，如下例所示：

```
spring:
  cloud:
    zookeeper:
      connect-string: localhost:2181
```

现在可以使用`DiscoveryClient`、`@LoadBalanced RestTemplate`或`@LoadBalanced WebClient.Builder`从 ZooKeeper 检索服务和实例数据，如以下示例所示：

```
@Autowired
private DiscoveryClient discoveryClient;

public String serviceUrl() {
    List<ServiceInstance> list = discoveryClient.getInstances("STORES");
    if (list != null && list.size() > 0 ) {
        return list.get(0).getUri().toString();
    }
    return null;
}
```

### 1.2.分布式配置使用

要在应用程序中使用这些特性，你可以将其构建为依赖于`spring-cloud-zookeeper-core`和`spring-cloud-zookeeper-config`的 Spring 引导应用程序。添加依赖项最方便的方法是使用 Spring 引导启动器：`org.springframework.cloud:spring-cloud-starter-zookeeper-config`。我们建议使用依赖管理和`spring-boot-starter-parent`。下面的示例显示了典型的 Maven 配置：

POM.xml

```
<project>
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>{spring-boot-version}</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>

  <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-zookeeper-config</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>${spring-cloud.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
</project>
```

下面的示例显示了一个典型的 Gradle 设置：

构建。 Gradle

```
plugins {
  id 'org.springframework.boot' version ${spring-boot-version}
  id 'io.spring.dependency-management' version ${spring-dependency-management-version}
  id 'java'
}

repositories {
  mavenCentral()
}

dependencies {
  implementation 'org.springframework.cloud:spring-cloud-starter-zookeeper-config'
  testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
dependencyManagement {
  imports {
    mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
  }
}
```

|   |根据你使用的版本，你可能需要调整你的项目中使用的 Apache ZooKeeper 版本。<br/>你可以在[安装动物园管理员部分](#spring-cloud-zookeeper-install)中阅读有关它的更多信息。|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

现在，你可以创建一个标准的 Spring 启动应用程序，例如下面的 HTTP 服务器：

```
@SpringBootApplication
@RestController
public class Application {

    @GetMapping("/")
    public String home() {
        return "Hello World!";
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}
```

应用程序从 ZooKeeper 检索配置数据。

|   |如果使用 Spring Cloud ZooKeeper Config，则需要设置`spring.config.import`属性才能绑定到 ZooKeeper。<br/>你可以在[Spring Boot Config Data Import section](#config-data-import)中阅读有关它的更多信息。|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

## 2.安装 ZooKeeper

有关如何安装 ZooKeeper 的说明，请参见[安装文档](https://zookeeper.apache.org/doc/current/zookeeperStarted.html)。

Spring Cloud ZooKeeper 在幕后使用 Apache 策展人。虽然 ZooKeeper3.5.x 仍然被 ZooKeeper 开发团队认为是“测试版”，但现实情况是，许多用户都在生产中使用它。然而，ZooKeeper3.4.x 也在生产中使用。在 Apache Curator4.0 之前，两个版本的 ZooKeeper 都是通过两个版本的 Apache Curator 支持的。从 Curator4.0 开始，ZooKeeper 的两个版本都通过相同的 Curator 库支持。

如果要与版本 3.4 集成，则需要更改`curator`附带的 ZooKeeper 依赖项，从而更改`spring-cloud-zookeeper`。要做到这一点，只需排除该依赖关系，并添加如下所示的 3.4.x 版本。

Maven

```
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zookeeper-all</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.4.12</version>
    <exclusions>
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </exclusion>
    </exclusions>
</dependency>
```

Gradle

```
compile('org.springframework.cloud:spring-cloud-starter-zookeeper-all') {
  exclude group: 'org.apache.zookeeper', module: 'zookeeper'
}
compile('org.apache.zookeeper:zookeeper:3.4.12') {
  exclude group: 'org.slf4j', module: 'slf4j-log4j12'
}
```

## 3.使用 ZooKeeper 进行服务发现

服务发现是基于微服务的体系结构的关键原则之一。尝试手动配置每个客户机或某种形式的约定可能很难做到，并且可能很脆弱。[Curator](https://curator.apache.org)（ZooKeeper 的 Java 库）通过[服务发现扩展](https://curator.apache.org/curator-x-discovery/)提供服务发现。 Spring Cloud ZooKeeper 将此扩展用于服务注册和发现。

### 3.1.激活

包括对`org.springframework.cloud:spring-cloud-starter-zookeeper-discovery`的依赖可以实现自动配置，从而设置 Spring Cloud ZooKeeper 发现。

|   |对于 Web 功能，你仍然需要包含`org.springframework.boot:spring-boot-starter-web`。|
|---|---------------------------------------------------------------------------------------------------|

|   |在使用 ZooKeeper 的 3.4 版本时，你需要更改<br/>包含依赖项的方式，如[here](#spring-cloud-zookeeper-install)所述。|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------|

### 3.2.在动物园管理员处注册

当客户机向 ZooKeeper 注册时，它提供有关自身的元数据（如主机和端口、ID 和名称）。

下面的示例展示了一个 ZooKeeper 客户端：

```
@SpringBootApplication
@RestController
public class Application {

    @RequestMapping("/")
    public String home() {
        return "Hello world";
    }

    public static void main(String[] args) {
        new SpringApplicationBuilder(Application.class).web(true).run(args);
    }

}
```

|   |前面的示例是一个普通的引导应用程序 Spring。|
|---|----------------------------------------------------------|

如果 ZooKeeper 位于`localhost:2181`以外的地方，则配置必须提供服务器的位置，如下例所示：

应用程序.yml

```
spring:
  cloud:
    zookeeper:
      connect-string: localhost:2181
```

|   |如果使用[Spring Cloud Zookeeper Config](#spring-cloud-zookeeper-config)，则前面示例中显示的<br/>值需要在`bootstrap.yml`而不是`应用程序.yml`中。|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

默认的服务名、实例 ID 和端口（取自`Environment`）分别是`${spring.application.name}`、 Spring 上下文 ID 和`${server.port}`。

在 Classpath 上具有`spring-cloud-starter-zookeeper-discovery`使得该应用程序既可以成为 ZooKeeper“服务”（即它自己注册），也可以成为“客户端”（即它可以查询 ZooKeeper 以定位其他服务）。

如果你想禁用 ZooKeeper 发现客户端，可以将`spring.cloud.zookeeper.discovery.enabled`设置为`false`。

### 3.3.使用 DiscoveryClient

Spring Cloud 支持[Feign](https://github.com/spring-cloud/spring-cloud-netflix/blob/master/docs/src/main/asciidoc/spring-cloud-netflix.adoc#spring-cloud-feign)（一个 REST 客户端构建器）、[[ Spring `RestTemplate`]（https://github.com/ Spring-cloud/ Spring-cloud-netflix/blob/master/DOCS/SRC/main/ascii）和[Spring WebFlux](https://cloud.spring.io/spring-cloud-commons/reference/html/#loadbalanced-webclient)，使用逻辑服务名称而不是物理 URL。

你也可以使用`org.springframework.cloud.client.discovery.DiscoveryClient`，它为不特定于 Netflix 的发现客户端提供了一个简单的 API，如下例所示：

```
@Autowired
private DiscoveryClient discoveryClient;

public String serviceUrl() {
    List<ServiceInstance> list = discoveryClient.getInstances("STORES");
    if (list != null && list.size() > 0 ) {
        return list.get(0).getUri().toString();
    }
    return null;
}
```

## 4. Using Spring Cloud Zookeeper with Spring Cloud Components

假装、 Spring Cloud网关和 Spring Cloud负载均衡器都与 Spring Cloud ZooKeeper 一起工作。

### 4.1. Spring Cloud LoadBalancer with Zookeeper

Spring Cloud ZooKeeper 提供了 Spring Cloud LoadBalancer`ServiceInstanceListSupplier`的实现方式。当你使用`spring-cloud-starter-zookeeper-discovery`时， Spring Cloud负载平衡器被自动配置为默认使用`ZookeeperServiceInstanceListSupplier`。

|   |如果你以前在 ZooKeeper 中使用 StickyRule，则当前堆栈中的 stickyRule<br/>中的替换项是 SC LoadBalancer 中的`SameInstancePreferenceServiceInstanceListSupplier`。你可以在[Spring Cloud Commons documentation](https://docs.spring.io/spring-cloud-commons/docs/current/reference/html/#spring-cloud-loadbalancer)中阅读有关如何设置它的内容。|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

## 5. Spring Cloud Zookeeper and Service Registry

Spring Cloud ZooKeeper 实现了`ServiceRegistry`接口，允许开发人员以编程的方式注册任意服务。

`ServiceInstanceRegistration`类提供了一个`builder()`方法来创建`Registration`对象，该对象可以由`ServiceRegistry`使用，如以下示例所示：

```
@Autowired
private ZookeeperServiceRegistry serviceRegistry;

public void registerThings() {
    ZookeeperRegistration registration = ServiceInstanceRegistration.builder()
            .defaultUriSpec()
            .address("anyUrl")
            .port(10)
            .name("/a/b/c/d/anotherservice")
            .build();
    this.serviceRegistry.register(registration);
}
```

### 5.1.实例状态

Netflix Eureka 支持在服务器上注册`OUT_OF_SERVICE`实例。这些实例不作为活动服务实例返回。这对于诸如蓝色/绿色部署之类的行为很有用。（注意，Curator 服务发现配方不支持此行为。）利用灵活的有效负载， Spring Cloud ZooKeeper 可以通过更新一些特定的元数据，然后在 Spring Cloud LoadBalancer中对该元数据进行过滤来实现。`ZookeeperServiceInstanceListSupplier`过滤掉所有不等于`UP`的非空实例状态。如果实例状态字段为空，则认为它是`UP`，用于向后兼容。要更改实例的状态，请将`POST`与`OUT_OF_SERVICE`连接到`ServiceRegistry`实例状态执行器端点，如以下示例所示：

```
$ http POST http://localhost:8081/service-registry status=OUT_OF_SERVICE
```

|   |前面的示例使用[httpie.org](https://httpie.org)中的`http`命令。|
|---|------------------------------------------------------------------------------------|

## 6.动物园管理员依赖关系

以下主题涵盖了如何使用 Spring Cloud ZooKeeper 依赖项：

* [使用 ZooKeeper 依赖项](#spring-cloud-zookeeper-dependencies-using)

* [激活 ZooKeeper 依赖项](#spring-cloud-zookeeper-dependencies-activating)

* [设置 ZooKeeper 依赖项](#spring-cloud-zookeeper-dependencies-setting-up)

* [Configuring Spring Cloud Zookeeper Dependencies](#spring-cloud-zookeeper-dependencies-configuring)

### 6.1.使用 ZooKeeper 依赖项

Spring Cloud ZooKeeper 为你提供了一种可能性，可以将你的应用程序的依赖关系作为属性提供。作为依赖关系，你可以了解注册在 ZooKeeper 中并希望通过[Feign](https://github.com/spring-cloud/spring-cloud-netflix/blob/master/docs/src/main/asciidoc/spring-cloud-netflix.adoc#spring-cloud-feign)（一个 REST 客户机生成器）调用的其他应用程序，[ Spring `RestTemplate`]（https://github.com/ Spring-cloud/ Spring-cloud/ Spring-cloud-netflix/blob/master/DOCS/SRC/main/ascii）和[Spring WebFlux](https://cloud.spring.io/spring-cloud-commons/reference/html/#loadbalanced-webclient)。

你还可以使用 ZooKeeper Dependency Watchers 功能来控制和监视你的依赖关系的状态。

### 6.2.激活 ZooKeeper 依赖项

包含对`org.springframework.cloud:spring-cloud-starter-zookeeper-discovery`的依赖项，可以实现自动配置，从而设置 Spring Cloud ZooKeeper 依赖项。即使你在属性中提供了依赖关系，也可以关闭依赖关系。为此，将`spring.cloud.zookeeper.dependency.enabled`属性设置为 false（默认设置为`true`）。

### 6.3.设置 ZooKeeper 依赖项

考虑下面的依赖关系表示示例：

application.yml

```
spring.application.name: yourServiceName
spring.cloud.zookeeper:
  dependencies:
    newsletter:
      path: /path/where/newsletter/has/registered/in/zookeeper
      loadBalancerType: ROUND_ROBIN
      contentTypeTemplate: application/vnd.newsletter.$version+json
      version: v1
      headers:
        header1:
            - value1
        header2:
            - value2
      required: false
      stubs: org.springframework:foo:stubs
    mailing:
      path: /path/where/mailing/has/registered/in/zookeeper
      loadBalancerType: ROUND_ROBIN
      contentTypeTemplate: application/vnd.mailing.$version+json
      version: v1
      required: true
```

接下来的几节将逐一介绍依赖关系的每个部分。根属性名为`spring.cloud.zookeeper.dependencies`。

#### 6.3.1.别名

在根属性下面，你必须将每个依赖项表示为别名。这是由于 Spring Cloud LoadBalancer 的限制，它要求将应用程序 ID 放置在 URL 中。因此，你不能通过任何复杂的路径，例如`/myApp/myRoute/name`）。别名是你使用的名称，而不是用于`DiscoveryClient`，`Feign`或`RestTemplate`的`serviceId`。

在前面的示例中，别名是`newsletter`和`mailing`。下面的示例显示了使用`newsletter`别名的假装用法：

```
@FeignClient("newsletter")
public interface NewsletterService {
        @RequestMapping(method = RequestMethod.GET, value = "/newsletter")
        String getNewsletters();
}
```

#### 6.3.2.路径

该路径由`path`YAML 属性表示，并且是在 ZooKeeper 下注册依赖项的路径。正如[上一节](#spring-cloud-zookeeper-dependencies-setting-up-aliases)中所描述的， Spring Cloud LoadBalancer 在 URL 上运行。因此，此路径不符合其需求。这就是为什么 Spring Cloud ZooKeeper 将别名映射到正确的路径。

#### 6.3.3.负载平衡器类型

负载均衡器类型由`loadBalancerType`YAML 属性表示。

如果你知道在调用这个特定的依赖项时必须应用哪种负载平衡策略，那么你可以在 YAML 文件中提供它，并且它会自动应用。你可以选择以下一种负载平衡策略：

* sticky:一旦选择，实例总是被调用。

* 随机：随机选择一个实例。

* Round\_Robin:一遍又一遍地迭代实例。

#### 6.3.4.`Content-Type`模板和版本

`Content-Type`模板和版本由`contentTypeTemplate`和`version`YAML 属性表示。

如果在`Content-Type`头中对 API 进行版本，则不希望将此头添加到每个请求中。此外，如果你想调用一个新版本的 API，那么你不希望围绕你的代码 ROAM 来提高 API 版本。这就是为什么可以为`contentTypeTemplate`提供一个特殊的`$version`占位符。这个占位符将由`version`YAML 属性的值来填充。考虑以下`contentTypeTemplate`的示例：

```
application/vnd.newsletter.$version+json
```

进一步考虑以下`version`:

```
v1
```

结合`contentTypeTemplate`和版本，将为每个请求创建`Content-Type`头，如下所示：

```
application/vnd.newsletter.v1+json
```

#### 6.3.5.默认标头

默认的头文件由 YAML 中的`headers`映射表示。

有时，对依赖项的每次调用都需要设置一些默认的标头。要在代码中不这样做，你可以在 YAML 文件中设置它们，如以下示例`headers`部分所示：

```
headers:
    Accept:
        - text/html
        - application/xhtml+xml
    Cache-Control:
        - no-cache
```

该`headers`部分导致在 HTTP 请求中添加带有适当的值列表的`Accept`和`Cache-Control`标题。

#### 6.3.6.所需依赖项

在 YAML 中，所需的依赖项由`required`属性表示。

如果在启动应用程序时需要启动某个依赖项，则可以在 YAML 文件中设置`required: true`属性。

如果你的应用程序无法在引导期间定位所需的依赖项，那么它将抛出一个异常，并且 Spring 上下文将无法设置。换句话说，如果所需的依赖项未在 ZooKeeper 中注册，则应用程序无法启动。

你可以阅读更多关于 Spring Cloud ZooKeeper Presence Checker[在本文的后面部分](#spring-cloud-zookeeper-dependency-watcher-presence-checker)的信息。

#### 6.3.7.小作品

可以为 jar 包含依赖项存根的 jar 提供一个以冒号分隔的路径，如以下示例所示：

`stubs: org.springframework:myApp:stubs`

地点：

* `org.springframework`是`groupId`。

* `myApp`是`artifactId`。

* `stubs`是分类器。（注意，`stubs`是默认值。

因为`stubs`是缺省分类器，所以前面的示例等于下面的示例：

`stubs: org.springframework:myApp`

### 6.4. Configuring Spring Cloud Zookeeper Dependencies

你可以设置以下属性来启用或禁用 ZooKeeper 依赖项功能的部分功能：

* `spring.cloud.zookeeper.dependencies`:如果未设置此属性，则不能使用 ZooKeeper 依赖项。

* `spring.cloud.zookeeper.dependency.loadbalancer.enabled`（默认启用）：开启特定于 ZooKeeper 的定制负载平衡策略，包括`ZookeeperServiceInstanceListSupplier`和基于依赖项的负载平衡`RestTemplate`设置。

* `spring.cloud.zookeeper.dependency.headers.enabled`（默认情况下启用）：此属性注册了`FeignBlockingLoadBalancerClient`，该属性会自动将适当的标题和内容类型附加到它们的版本中，如依赖项配置中所示。如果没有这个设置，这两个参数将无法工作。

* `spring.cloud.zookeeper.dependency.resttemplate.enabled`（默认情况下启用）：启用时，此属性修改`@LoadBalanced`-带注释的`RestTemplate`的请求标头，使其传递带有依赖项配置中设置的版本的标头和内容类型。如果没有这个设置，这两个参数将无法工作。

## 7. Spring Cloud Zookeeper Dependency Watcher

依赖项监视器机制允许你将侦听器注册到依赖项。实际上，该功能是`Observator`模式的一种实现。当依赖项发生变化时，它的状态（向上或向下），可以应用一些自定义逻辑。

### 7.1.激活

Spring Cloud ZooKeeper 依赖项功能需要被启用，以便你使用依赖项观察机制。

### 7.2.注册侦听器

要注册一个侦听器，你必须实现一个名为`org.springframework.cloud.zookeeper.discovery.watcher.DependencyWatcherListener`的接口，并将其注册为 Bean。该接口为你提供了一种方法：

```
void stateChanged(String dependencyName, DependencyState newState);
```

如果你想注册一个特定依赖项的侦听器，那么`dependencyName`将是你的具体实现的鉴别器。`newState`为你提供有关你的依赖关系是否已更改为`CONNECTED`或`DISCONNECTED`的信息。

### 7.3.使用临场感检查器

与依赖项监视器绑定的是名为存在检查器的功能。它允许你在应用程序启动时提供自定义行为，以便根据依赖关系的状态做出反应。

抽象`org.springframework.cloud.zookeeper.discovery.watcher.presence.DependencyPresenceOnStartupVerifier`类的默认实现是`org.springframework.cloud.zookeeper.discovery.watcher.presence.DefaultDependencyPresenceOnStartupVerifier`，其工作方式如下。

1. 如果依赖项被标记为 US`required`，并且不在 ZooKeeper 中，那么当应用程序启动时，它将抛出一个异常并关闭。

2. 如果依赖项不是`required`，则`org.springframework.cloud.zookeeper.discovery.watcher.presence.LogMissingDependencyChecker`记录在`WARN`级别缺少依赖项。

因为`DefaultDependencyPresenceOnStartupVerifier`只有在没有`DependencyPresenceOnStartupVerifier`类型的 Bean 时才注册，所以可以重写此功能。

## 8.使用 ZooKeeper 的分布式配置

ZooKeeper 提供了一个[层次命名空间](https://zookeeper.apache.org/doc/current/zookeeperOver.html#sc_dataModelNameSpace)，它允许客户端存储任意数据，例如配置数据。 Spring Cloud ZooKeeper Config 是[配置服务器和客户端](https://github.com/spring-cloud/spring-cloud-config)的一种替代方案。在特殊的“引导”阶段，将配置加载到 Spring 环境中。默认情况下，配置存储在`/config`名称空间中。基于应用程序的名称和活动配置文件，创建了多个`PropertySource`实例，以模拟解析属性的 Spring Cloud配置顺序。例如，名称为`testApp`且配置文件为`dev`的应用程序具有为其创建的以下属性源：

* `config/testApp,dev`

* `config/testApp`

* `config/application,dev`

* `config/application`

最具体的属性源位于顶部，而最不具体的属性源位于底部。`config/application`命名空间中的属性应用于所有使用 ZooKeeper 进行配置的应用程序。`config/testApp`命名空间中的属性仅对名为`testApp`的服务实例可用。

当前在启动应用程序时读取配置。向`/refresh`发送一个 HTTP`POST`请求会导致重新加载配置。监视配置名称空间（ZooKeeper 支持的）当前未实现。

### 8.1.激活

包括对`org.springframework.cloud:spring-cloud-starter-zookeeper-config`的依赖可以实现自动配置，从而设置 Spring Cloud ZooKeeper 配置。

|   |在使用 ZooKeeper 的 3.4 版本时，你需要更改<br/>包含依赖项的方式，如[here](#spring-cloud-zookeeper-install)所述。|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------|

### 8.2. Spring Boot Config Data Import

Spring Boot2.4 引入了一种通过`spring.config.import`属性导入配置数据的新方法。这是现在从 ZooKeeper 获得配置的默认方式。

要在应用程序中可选地连接到 ZooKeeper 以进行配置，请设置以下内容：

应用程序.属性

```
spring.config.import=optional:zookeeper:
```

这将在“localhost:2181”的默认位置连接到 ZooKeeper。如果无法连接到 ZooKeeper，删除`optional:`前缀将导致 ZooKeeper 配置失败。要更改 ZooKeeper Config 的连接属性，可以设置`spring.cloud.zookeeper.connect-string`，也可以将 connect 字符串添加到`spring.config.import`语句中，例如，`spring.config.import=optional:zookeeper:myhost:2818`。导入属性中的位置优先于`connect-string`属性。

ZooKeeper Config 将尝试根据`spring.cloud.zookeeper.config.name`（默认为`spring.application.name`属性的值）和`spring.cloud.zookeeper.config.default-context`（默认为`application`）从四个自动上下文加载值。如果你希望指定上下文，而不是使用计算的上下文，那么可以将该信息添加到`spring.config.import`语句中。

application.properties

```
spring.config.import=optional:zookeeper:myhost:2181/contextone;/context/two
```

这将可选地只从`/contextone`和`/context/two`加载配置。

|   |通过`spring.config.import`导入 Spring 引导配置数据方法所需的`bootstrap`文件（属性或 YAML）是**不是**。|
|---|--------------------------------------------------------------------------------------------------------------------------------------|

### 8.3.定制

可以通过设置以下属性来定制 ZooKeeper 配置：

```
spring:
  cloud:
    zookeeper:
      config:
        enabled: true
        root: configuration
        defaultContext: apps
        profileSeparator: '::'
```

* `enabled`:将该值设置为`false`将禁用 ZooKeeper 配置。

* `root`:设置配置值的基本名称空间。

* `defaultContext`:设置所有应用程序使用的名称。

* `profileSeparator`:设置用于在具有配置文件的属性源中分隔配置文件名称的分隔符的值。

|   |如果你已经设置了`spring.cloud.bootstrap.enabled=true`或`spring.config.use-legacy-processing=true`，或者包含了`spring-cloud-starter-bootstrap`，那么上述值将需要放置在`bootstrap.yml`中，而不是`application.yml`中。|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

### 8.4.访问控制列表（ACLS）

通过调用`CuratorFramework` Bean 的`addAuthInfo`方法，可以为 ZooKeeper ACLS 添加身份验证信息。实现这一点的一种方法是提供你自己的`CuratorFramework` Bean，如下例所示：

```
@BoostrapConfiguration
public class CustomCuratorFrameworkConfig {

  @Bean
  public CuratorFramework curatorFramework() {
    CuratorFramework curator = new CuratorFramework();
    curator.addAuthInfo("digest", "user:password".getBytes());
    return curator;
  }

}
```

请参阅[ZookeeperAutoConfiguration 类](https://github.com/spring-cloud/spring-cloud-zookeeper/blob/master/spring-cloud-zookeeper-core/src/main/java/org/springframework/cloud/zookeeper/ZookeeperAutoConfiguration.java)以查看`CuratorFramework` Bean 的默认配置。

或者，你可以从依赖于现有`CuratorFramework` Bean 的类中添加凭据，如以下示例所示：

```
@BoostrapConfiguration
public class DefaultCuratorFrameworkConfig {

  public ZookeeperConfig(CuratorFramework curator) {
    curator.addAuthInfo("digest", "user:password".getBytes());
  }

}
```

此 Bean 的创建必须在引导阶段发生。你可以注册要在此阶段运行的配置类，方法是用`@BootstrapConfiguration`对它们进行注释，并将它们包括在一个逗号分隔的列表中，你将该列表设置为`Party-INF/ Spring.Factories`文件中`org.springframework.cloud.bootstrap.BootstrapConfiguration`属性的值，如以下示例所示：

resources/META-INF/spring.factories

```
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
my.project.CustomCuratorFrameworkConfig,\
my.project.DefaultCuratorFrameworkConfig
```