584 lines
31 KiB
XML
584 lines
31 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<?asciidoc-toc?>
|
|
<?asciidoc-numbered?>
|
|
<book xmlns="http://docbook.org/ns/docbook" xmlns:xl="http://www.w3.org/1999/xlink" version="5.0" xml:lang="en">
|
|
<info>
|
|
<title>Spring Cloud Zookeeper</title>
|
|
<date>2018-06-19</date>
|
|
</info>
|
|
<preface>
|
|
<title></title>
|
|
<simpara>This project provides Zookeeper integrations for Spring Boot applications through
|
|
autoconfiguration and binding to the Spring Environment and other Spring programming model
|
|
idioms. With a few annotations, you can quickly enable and configure the common patterns
|
|
inside your application and build large distributed systems with Zookeeper based
|
|
components. The provided patterns include Service Discovery and Configuration. Integration
|
|
with Spring Cloud Netflix provides Intelligent Routing (Zuul), Client Side Load Balancing
|
|
(Ribbon), and Circuit Breaker (Hystrix).</simpara>
|
|
</preface>
|
|
<chapter xml:id="spring-cloud-zookeeper-install">
|
|
<title>Install Zookeeper</title>
|
|
<simpara>See the <link xl:href="http://zookeeper.apache.org/doc/current/zookeeperStarted.html">installation
|
|
documentation</link> for instructions on how to install Zookeeper.</simpara>
|
|
<simpara>Spring Cloud Zookeeper uses Apache Curator behind the scenes.
|
|
While Zookeeper 3.5.x is still considered "beta" by the Zookeeper development team,
|
|
the reality is that it is used in production by many users.
|
|
However, Zookeeper 3.4.x is also used in production.
|
|
Prior to Apache Curator 4.0, both versions of Zookeeper were supported via two versions of Apache Curator.
|
|
Starting with Curator 4.0 both versions of Zookeeper are supported via the same Curator libraries.</simpara>
|
|
<simpara>In case you are integrating with version 3.4 you need to change the Zookeeper dependency
|
|
that comes shipped with <literal>curator</literal>, and thus <literal>spring-cloud-zookeeper</literal>.
|
|
To do so simply exclude that dependency and add the 3.4.x version like shown below.</simpara>
|
|
<formalpara>
|
|
<title>maven</title>
|
|
<para>
|
|
<programlisting language="xml" linenumbering="unnumbered"><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></programlisting>
|
|
</para>
|
|
</formalpara>
|
|
<formalpara>
|
|
<title>gradle</title>
|
|
<para>
|
|
<programlisting language="groovy" linenumbering="unnumbered">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'
|
|
}</programlisting>
|
|
</para>
|
|
</formalpara>
|
|
</chapter>
|
|
<chapter xml:id="spring-cloud-zookeeper-discovery">
|
|
<title>Service Discovery with Zookeeper</title>
|
|
<simpara>Service Discovery is one of the key tenets of a microservice based architecture. Trying to
|
|
hand-configure each client or some form of convention can be difficult to do and can be
|
|
brittle. <link xl:href="http://curator.apache.org">Curator</link>(A Java library for Zookeeper) provides Service
|
|
Discovery through a <link xl:href="http://curator.apache.org/curator-x-discovery/">Service Discovery
|
|
Extension</link>. Spring Cloud Zookeeper uses this extension for service registration and
|
|
discovery.</simpara>
|
|
<section xml:id="_activating">
|
|
<title>Activating</title>
|
|
<simpara>Including a dependency on
|
|
<literal>org.springframework.cloud:spring-cloud-starter-zookeeper-discovery</literal> enables
|
|
autoconfiguration that sets up Spring Cloud Zookeeper Discovery.</simpara>
|
|
<note>
|
|
<simpara>For web functionality, you still need to include
|
|
<literal>org.springframework.boot:spring-boot-starter-web</literal>.</simpara>
|
|
</note>
|
|
<caution>
|
|
<simpara>When working with version 3.4 of Zookeeper you need to change
|
|
the way you include the dependency as described <link linkend="spring-cloud-zookeeper-install">here</link>.</simpara>
|
|
</caution>
|
|
</section>
|
|
<section xml:id="_registering_with_zookeeper">
|
|
<title>Registering with Zookeeper</title>
|
|
<simpara>When a client registers with Zookeeper, it provides metadata (such as host and port, ID,
|
|
and name) about itself.</simpara>
|
|
<simpara>The following example shows a Zookeeper client:</simpara>
|
|
<programlisting language="java" linenumbering="unnumbered">@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);
|
|
}
|
|
|
|
}</programlisting>
|
|
<note>
|
|
<simpara>The preceding example is a normal Spring Boot application.</simpara>
|
|
</note>
|
|
<simpara>If Zookeeper is located somewhere other than <literal>localhost:2181</literal>, the configuration must
|
|
provide the location of the server, as shown in the following example:</simpara>
|
|
<formalpara>
|
|
<title>application.yml</title>
|
|
<para>
|
|
<programlisting language="yml" linenumbering="unnumbered">spring:
|
|
cloud:
|
|
zookeeper:
|
|
connect-string: localhost:2181</programlisting>
|
|
</para>
|
|
</formalpara>
|
|
<caution>
|
|
<simpara>If you use <link linkend="spring-cloud-zookeeper-config">Spring Cloud Zookeeper Config</link>, the
|
|
values shown in the preceding example need to be in <literal>bootstrap.yml</literal> instead of
|
|
<literal>application.yml</literal>.</simpara>
|
|
</caution>
|
|
<simpara>The default service name, instance ID, and port (taken from the <literal>Environment</literal>) are
|
|
<literal>${spring.application.name}</literal>, the Spring Context ID, and <literal>${server.port}</literal>, respectively.</simpara>
|
|
<simpara>Having <literal>spring-cloud-starter-zookeeper-discovery</literal> on the classpath makes the app into both
|
|
a Zookeeper “service” (that is, it registers itself) and a “client” (that is, it can
|
|
query Zookeeper to locate other services).</simpara>
|
|
<simpara>If you would like to disable the Zookeeper Discovery Client, you can set
|
|
<literal>spring.cloud.zookeeper.discovery.enabled</literal> to <literal>false</literal>.</simpara>
|
|
</section>
|
|
<section xml:id="_using_the_discoveryclient">
|
|
<title>Using the DiscoveryClient</title>
|
|
<simpara>Spring Cloud has support for
|
|
<link xl:href="https://github.com/spring-cloud/spring-cloud-netflix/blob/master/docs/src/main/asciidoc/spring-cloud-netflix.adoc#spring-cloud-feign">Feign</link>
|
|
(a REST client builder) and
|
|
<link xl:href="https://github.com/spring-cloud/spring-cloud-netflix/blob/master/docs/src/main/asciidoc/spring-cloud-netflix.adoc#spring-cloud-ribbon">Spring
|
|
<literal>RestTemplate</literal></link>, using logical service names instead of physical URLs.</simpara>
|
|
<simpara>You can also use the <literal>org.springframework.cloud.client.discovery.DiscoveryClient</literal>, which
|
|
provides a simple API for discovery clients that is not specific to Netflix, as shown in
|
|
the following example:</simpara>
|
|
<programlisting language="java" linenumbering="unnumbered">@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;
|
|
}</programlisting>
|
|
</section>
|
|
</chapter>
|
|
<chapter xml:id="spring-cloud-zookeeper-netflix">
|
|
<title>Using Spring Cloud Zookeeper with Spring Cloud Netflix Components</title>
|
|
<simpara>Spring Cloud Netflix supplies useful tools that work regardless of which <literal>DiscoveryClient</literal>
|
|
implementation you use. Feign, Turbine, Ribbon, and Zuul all work with Spring Cloud
|
|
Zookeeper.</simpara>
|
|
<section xml:id="_ribbon_with_zookeeper">
|
|
<title>Ribbon with Zookeeper</title>
|
|
<simpara>Spring Cloud Zookeeper provides an implementation of Ribbon’s <literal>ServerList</literal>. When you use
|
|
the <literal>spring-cloud-starter-zookeeper-discovery</literal>, Ribbon is autoconfigured to use the
|
|
<literal>ZookeeperServerList</literal> by default.</simpara>
|
|
</section>
|
|
</chapter>
|
|
<chapter xml:id="spring-cloud-zookeeper-service-registry">
|
|
<title>Spring Cloud Zookeeper and Service Registry</title>
|
|
<simpara>Spring Cloud Zookeeper implements the <literal>ServiceRegistry</literal> interface, letting developers
|
|
register arbitrary services in a programmatic way.</simpara>
|
|
<simpara>The <literal>ServiceInstanceRegistration</literal> class offers a <literal>builder()</literal> method to create a
|
|
<literal>Registration</literal> object that can be used by the <literal>ServiceRegistry</literal>, as shown in the following
|
|
example:</simpara>
|
|
<programlisting language="java" linenumbering="unnumbered">@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);
|
|
}</programlisting>
|
|
<section xml:id="_instance_status">
|
|
<title>Instance Status</title>
|
|
<simpara>Netflix Eureka supports having instances that are <literal>OUT_OF_SERVICE</literal> registered with the
|
|
server. These instances are not returned as active service instances. This is useful for
|
|
behaviors such as blue/green deployments. (Note that the Curator Service Discovery recipe
|
|
does not support this behavior.) Taking advantage of the flexible payload has let Spring
|
|
Cloud Zookeeper implement <literal>OUT_OF_SERVICE</literal> by updating some specific metadata and then
|
|
filtering on that metadata in the Ribbon <literal>ZookeeperServerList</literal>. The <literal>ZookeeperServerList</literal>
|
|
filters out all non-null instance statuses that do not equal <literal>UP</literal>. If the instance status
|
|
field is empty, it is considered to be <literal>UP</literal> for backwards compatibility. To change the
|
|
status of an instance, make a <literal>POST</literal> with <literal>OUT_OF_SERVICE</literal> to the <literal>ServiceRegistry</literal>
|
|
instance status actuator endpoint, as shown in the following example:</simpara>
|
|
<programlisting language="sh" linenumbering="unnumbered">$ http POST http://localhost:8081/service-registry status=OUT_OF_SERVICE</programlisting>
|
|
<note>
|
|
<simpara>The preceding example uses the <literal>http</literal> command from <link xl:href="https://httpie.org">https://httpie.org</link>.</simpara>
|
|
</note>
|
|
</section>
|
|
</chapter>
|
|
<chapter xml:id="spring-cloud-zookeeper-dependencies">
|
|
<title>Zookeeper Dependencies</title>
|
|
<simpara>The following topics cover how to work with Spring Cloud Zookeeper dependencies:</simpara>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<simpara><xref linkend="spring-cloud-zookeeper-dependencies-using"/></simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara><xref linkend="spring-cloud-zookeeper-dependencies-activating"/></simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara><xref linkend="spring-cloud-zookeeper-dependencies-setting-up"/></simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara><xref linkend="spring-cloud-zookeeper-dependencies-configuring"/></simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<section xml:id="spring-cloud-zookeeper-dependencies-using">
|
|
<title>Using the Zookeeper Dependencies</title>
|
|
<simpara>Spring Cloud Zookeeper gives you a possibility to provide dependencies of your application
|
|
as properties. As dependencies, you can understand other applications that are registered
|
|
in Zookeeper and which you would like to call through
|
|
<link xl:href="https://github.com/spring-cloud/spring-cloud-netflix/blob/master/docs/src/main/asciidoc/spring-cloud-netflix.adoc#spring-cloud-feign">Feign</link>
|
|
(a REST client builder) and <link xl:href="https://github.com/spring-cloud/spring-cloud-netflix/blob/master/docs/src/main/asciidoc/spring-cloud-netflix.adoc#spring-cloud-ribbon">Spring <literal>RestTemplate</literal></link>.</simpara>
|
|
<simpara>You can also use the Zookeeper Dependency Watchers functionality to control and monitor
|
|
the state of your dependencies.</simpara>
|
|
</section>
|
|
<section xml:id="spring-cloud-zookeeper-dependencies-activating">
|
|
<title>Activating Zookeeper Dependencies</title>
|
|
<simpara>Including a dependency on
|
|
<literal>org.springframework.cloud:spring-cloud-starter-zookeeper-discovery</literal> enables
|
|
autoconfiguration that sets up Spring Cloud Zookeeper Dependencies. Even if you provide
|
|
the dependencies in your properties, you can turn off the dependencies. To do so, set the
|
|
<literal>spring.cloud.zookeeper.dependency.enabled</literal> property to false (it defaults to <literal>true</literal>).</simpara>
|
|
</section>
|
|
<section xml:id="spring-cloud-zookeeper-dependencies-setting-up">
|
|
<title>Setting up Zookeeper Dependencies</title>
|
|
<simpara>Consider the following example of dependency representation:</simpara>
|
|
<formalpara>
|
|
<title>application.yml</title>
|
|
<para>
|
|
<programlisting language="yml" linenumbering="unnumbered">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</programlisting>
|
|
</para>
|
|
</formalpara>
|
|
<simpara>The next few sections go through each part of the dependency one by one. The root property
|
|
name is <literal>spring.cloud.zookeeper.dependencies</literal>.</simpara>
|
|
<section xml:id="spring-cloud-zookeeper-dependencies-setting-up-aliases">
|
|
<title>Aliases</title>
|
|
<simpara>Below the root property you have to represent each dependency as an alias. This is due to
|
|
the constraints of Ribbon, which requires that the application ID be placed in the URL.
|
|
Consequently, you cannot pass any complex path, suchas <literal>/myApp/myRoute/name</literal>). The alias
|
|
is the name you use instead of the <literal>serviceId</literal> for <literal>DiscoveryClient</literal>, <literal>Feign</literal>, or
|
|
<literal>RestTemplate</literal>.</simpara>
|
|
<simpara>In the previous examples, the aliases are <literal>newsletter</literal> and <literal>mailing</literal>. The following
|
|
example shows Feign usage with a <literal>newsletter</literal> alias:</simpara>
|
|
<programlisting language="java" linenumbering="unnumbered">@FeignClient("newsletter")
|
|
public interface NewsletterService {
|
|
@RequestMapping(method = RequestMethod.GET, value = "/newsletter")
|
|
String getNewsletters();
|
|
}</programlisting>
|
|
</section>
|
|
<section xml:id="_path">
|
|
<title>Path</title>
|
|
<simpara>The path is represented by the <literal>path</literal> YAML property and is the path under which the
|
|
dependency is registered under Zookeeper. As described in the
|
|
<link linkend="spring-cloud-zookeeper-dependencies-setting-up-aliases">previous section</link>, Ribbon
|
|
operates on URLs. As a result, this path is not compliant with its requirement.
|
|
That is why Spring Cloud Zookeeper maps the alias to the proper path.</simpara>
|
|
</section>
|
|
<section xml:id="_load_balancer_type">
|
|
<title>Load Balancer Type</title>
|
|
<simpara>The load balancer type is represented by <literal>loadBalancerType</literal> YAML property.</simpara>
|
|
<simpara>If you know what kind of load-balancing strategy has to be applied when calling this
|
|
particular dependency, you can provide it in the YAML file, and it is automatically
|
|
applied. You can choose one of the following load balancing strategies:</simpara>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<simpara>STICKY: Once chosen, the instance is always called.</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>RANDOM: Picks an instance randomly.</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>ROUND_ROBIN: Iterates over instances over and over again.</simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
<section xml:id="__literal_content_type_literal_template_and_version">
|
|
<title><literal>Content-Type</literal> Template and Version</title>
|
|
<simpara>The <literal>Content-Type</literal> template and version are represented by the <literal>contentTypeTemplate</literal> and
|
|
<literal>version</literal> YAML properties.</simpara>
|
|
<simpara>If you version your API in the <literal>Content-Type</literal> header, you do not want to add this header
|
|
to each of your requests. Also, if you want to call a new version of the API, you do not
|
|
want to roam around your code to bump up the API version. That is why you can provide a
|
|
<literal>contentTypeTemplate</literal> with a special <literal>$version</literal> placeholder. That placeholder will be filled by the value of the
|
|
<literal>version</literal> YAML property. Consider the following example of a <literal>contentTypeTemplate</literal>:</simpara>
|
|
<screen>application/vnd.newsletter.$version+json</screen>
|
|
<simpara>Further consider the following <literal>version</literal>:</simpara>
|
|
<screen>v1</screen>
|
|
<simpara>The combination of <literal>contentTypeTemplate</literal> and version results in the creation of a
|
|
<literal>Content-Type</literal> header for each request, as follows:</simpara>
|
|
<screen>application/vnd.newsletter.v1+json</screen>
|
|
</section>
|
|
<section xml:id="_default_headers">
|
|
<title>Default Headers</title>
|
|
<simpara>Default headers are represented by the <literal>headers</literal> map in YAML.</simpara>
|
|
<simpara>Sometimes, each call to a dependency requires setting up of some default headers. To not
|
|
do that in code, you can set them up in the YAML file, as shown in the following example
|
|
<literal>headers</literal> section:</simpara>
|
|
<programlisting language="yml" linenumbering="unnumbered">headers:
|
|
Accept:
|
|
- text/html
|
|
- application/xhtml+xml
|
|
Cache-Control:
|
|
- no-cache</programlisting>
|
|
<simpara>That <literal>headers</literal> section results in adding the <literal>Accept</literal> and <literal>Cache-Control</literal> headers with
|
|
appropriate list of values in your HTTP request.</simpara>
|
|
</section>
|
|
<section xml:id="_required_dependencies">
|
|
<title>Required Dependencies</title>
|
|
<simpara>Required dependencies are represented by <literal>required</literal> property in YAML.</simpara>
|
|
<simpara>If one of your dependencies is required to be up when your application boots, you can set
|
|
the <literal>required: true</literal> property in the YAML file.</simpara>
|
|
<simpara>If your application cannot localize the required dependency during boot time, it throws an
|
|
exception, and the Spring Context fails to set up. In other words, your application cannot
|
|
start if the required dependency is not registered in Zookeeper.</simpara>
|
|
<simpara>You can read more about Spring Cloud Zookeeper Presence Checker
|
|
<link linkend="spring-cloud-zookeeper-dependency-watcher-presence-checker">later in this document</link>.</simpara>
|
|
</section>
|
|
<section xml:id="_stubs">
|
|
<title>Stubs</title>
|
|
<simpara>You can provide a colon-separated path to the JAR containing stubs of the dependency, as
|
|
shown in the following example:</simpara>
|
|
<simpara><literal>stubs: org.springframework:myApp:stubs</literal></simpara>
|
|
<simpara>where:</simpara>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<simpara><literal>org.springframework</literal> is the <literal>groupId</literal>.</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara><literal>myApp</literal> is the <literal>artifactId</literal>.</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara><literal>stubs</literal> is the classifier. (Note that <literal>stubs</literal> is the default value.)</simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<simpara>Because <literal>stubs</literal> is the default classifier, the preceding example is equal to the following
|
|
example:</simpara>
|
|
<simpara><literal>stubs: org.springframework:myApp</literal></simpara>
|
|
</section>
|
|
</section>
|
|
<section xml:id="spring-cloud-zookeeper-dependencies-configuring">
|
|
<title>Configuring Spring Cloud Zookeeper Dependencies</title>
|
|
<simpara>You can set the following properties to enable or disable parts of Zookeeper Dependencies
|
|
functionalities:</simpara>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<simpara><literal>spring.cloud.zookeeper.dependencies</literal>: If you do not set this property, you cannot use
|
|
Zookeeper Dependencies.</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara><literal>spring.cloud.zookeeper.dependency.ribbon.enabled</literal> (enabled by default): Ribbon requires
|
|
either explicit global configuration or a particular one for a dependency. By turning on
|
|
this property, runtime load balancing strategy resolution is possible, and you can use the
|
|
<literal>loadBalancerType</literal> section of the Zookeeper Dependencies. The configuration that needs
|
|
this property has an implementation of <literal>LoadBalancerClient</literal> that delegates to the
|
|
<literal>ILoadBalancer</literal> presented in the next bullet.</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara><literal>spring.cloud.zookeeper.dependency.ribbon.loadbalancer</literal> (enabled by default): Thanks to
|
|
this property, the custom <literal>ILoadBalancer</literal> knows that the part of the URI passed to Ribbon
|
|
might actually be the alias that has to be resolved to a proper path in Zookeeper. Without
|
|
this property, you cannot register applications under nested paths.</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara><literal>spring.cloud.zookeeper.dependency.headers.enabled</literal> (enabled by default): This property
|
|
registers a <literal>RibbonClient</literal> that automatically appends appropriate headers and content
|
|
types with their versions, as presented in the Dependency configuration. Without this
|
|
setting, those two parameters do not work.</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara><literal>spring.cloud.zookeeper.dependency.resttemplate.enabled</literal> (enabled by default): When
|
|
enabled, this property modifies the request headers of a <literal>@LoadBalanced</literal>-annotated
|
|
<literal>RestTemplate</literal> such that it passes headers and content type with the version set in
|
|
dependency configuration. Without this setting, those two parameters do not work.</simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
</chapter>
|
|
<chapter xml:id="spring-cloud-zookeeper-dependency-watcher">
|
|
<title>Spring Cloud Zookeeper Dependency Watcher</title>
|
|
<simpara>The Dependency Watcher mechanism lets you register listeners to your dependencies. The
|
|
functionality is, in fact, an implementation of the <literal>Observator</literal> pattern. When a
|
|
dependency changes, its state (to either UP or DOWN), some custom logic can be applied.</simpara>
|
|
<section xml:id="_activating_2">
|
|
<title>Activating</title>
|
|
<simpara>Spring Cloud Zookeeper Dependencies functionality needs to be enabled for you to use the
|
|
Dependency Watcher mechanism.</simpara>
|
|
</section>
|
|
<section xml:id="_registering_a_listener">
|
|
<title>Registering a Listener</title>
|
|
<simpara>To register a listener, you must implement an interface called
|
|
<literal>org.springframework.cloud.zookeeper.discovery.watcher.DependencyWatcherListener</literal> and
|
|
register it as a bean. The interface gives you one method:</simpara>
|
|
<programlisting language="java" linenumbering="unnumbered">void stateChanged(String dependencyName, DependencyState newState);</programlisting>
|
|
<simpara>If you want to register a listener for a particular dependency, the <literal>dependencyName</literal> would
|
|
be the discriminator for your concrete implementation. <literal>newState</literal> provides you with
|
|
information about whether your dependency has changed to <literal>CONNECTED</literal> or <literal>DISCONNECTED</literal>.</simpara>
|
|
</section>
|
|
<section xml:id="spring-cloud-zookeeper-dependency-watcher-presence-checker">
|
|
<title>Using the Presence Checker</title>
|
|
<simpara>Bound with the Dependency Watcher is the functionality called Presence Checker. It lets
|
|
you provide custom behavior when your application boots, to react according to the state
|
|
of your dependencies.</simpara>
|
|
<simpara>The default implementation of the abstract
|
|
<literal>org.springframework.cloud.zookeeper.discovery.watcher.presence.DependencyPresenceOnStartupVerifier</literal>
|
|
class is the
|
|
<literal>org.springframework.cloud.zookeeper.discovery.watcher.presence.DefaultDependencyPresenceOnStartupVerifier</literal>,
|
|
which works in the following way.</simpara>
|
|
<orderedlist numeration="arabic">
|
|
<listitem>
|
|
<simpara>If the dependency is marked us <literal>required</literal> and is not in Zookeeper, when your application
|
|
boots, it throws an exception and shuts down.</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara>If the dependency is not <literal>required</literal>, the
|
|
<literal>org.springframework.cloud.zookeeper.discovery.watcher.presence.LogMissingDependencyChecker</literal>
|
|
logs that the dependency is missing at the <literal>WARN</literal> level.</simpara>
|
|
</listitem>
|
|
</orderedlist>
|
|
<simpara>Because the <literal>DefaultDependencyPresenceOnStartupVerifier</literal> is registered only when there is
|
|
no bean of type <literal>DependencyPresenceOnStartupVerifier</literal>, this functionality can be
|
|
overridden.</simpara>
|
|
</section>
|
|
</chapter>
|
|
<chapter xml:id="spring-cloud-zookeeper-config">
|
|
<title>Distributed Configuration with Zookeeper</title>
|
|
<simpara>Zookeeper provides a
|
|
<link xl:href="http://zookeeper.apache.org/doc/current/zookeeperOver.html#sc_dataModelNameSpace">hierarchical namespace</link>
|
|
that lets clients store arbitrary data, such as configuration data. Spring Cloud Zookeeper
|
|
Config is an alternative to the
|
|
<link xl:href="https://github.com/spring-cloud/spring-cloud-config">Config Server and Client</link>.
|
|
Configuration is loaded into the Spring Environment during the special “bootstrap”
|
|
phase. Configuration is stored in the <literal>/config</literal> namespace by default. Multiple
|
|
<literal>PropertySource</literal> instances are created, based on the application’s name and the active
|
|
profiles, to mimic the Spring Cloud Config order of resolving properties. For example, an
|
|
application with a name of <literal>testApp</literal> and with the <literal>dev</literal> profile has the following property
|
|
sources created for it:</simpara>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<simpara><literal>config/testApp,dev</literal></simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara><literal>config/testApp</literal></simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara><literal>config/application,dev</literal></simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara><literal>config/application</literal></simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<simpara>The most specific property source is at the top, with the least specific at the bottom.
|
|
Properties in the <literal>config/application</literal> namespace apply to all applications that use
|
|
zookeeper for configuration. Properties in the <literal>config/testApp</literal> namespace are available
|
|
only to the instances of the service named <literal>testApp</literal>.</simpara>
|
|
<simpara>Configuration is currently read on startup of the application. Sending a HTTP <literal>POST</literal>
|
|
request to <literal>/refresh</literal> causes the configuration to be reloaded. Watching the configuration
|
|
namespace (which Zookeeper supports) is not currently implemented.</simpara>
|
|
<section xml:id="_activating_3">
|
|
<title>Activating</title>
|
|
<simpara>Including a dependency on
|
|
<literal>org.springframework.cloud:spring-cloud-starter-zookeeper-config</literal> enables
|
|
autoconfiguration that sets up Spring Cloud Zookeeper Config.</simpara>
|
|
<caution>
|
|
<simpara>When working with version 3.4 of Zookeeper you need to change
|
|
the way you include the dependency as described <link linkend="spring-cloud-zookeeper-install">here</link>.</simpara>
|
|
</caution>
|
|
</section>
|
|
<section xml:id="_customizing">
|
|
<title>Customizing</title>
|
|
<simpara>Zookeeper Config may be customized by setting the following properties:</simpara>
|
|
<formalpara>
|
|
<title>bootstrap.yml</title>
|
|
<para>
|
|
<programlisting language="yml" linenumbering="unnumbered">spring:
|
|
cloud:
|
|
zookeeper:
|
|
config:
|
|
enabled: true
|
|
root: configuration
|
|
defaultContext: apps
|
|
profileSeparator: '::'</programlisting>
|
|
</para>
|
|
</formalpara>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<simpara><literal>enabled</literal>: Setting this value to <literal>false</literal> disables Zookeeper Config.</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara><literal>root</literal>: Sets the base namespace for configuration values.</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara><literal>defaultContext</literal>: Sets the name used by all applications.</simpara>
|
|
</listitem>
|
|
<listitem>
|
|
<simpara><literal>profileSeparator</literal>: Sets the value of the separator used to separate the profile name in
|
|
property sources with profiles.</simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
<section xml:id="_access_control_lists_acls">
|
|
<title>Access Control Lists (ACLs)</title>
|
|
<simpara>You can add authentication information for Zookeeper ACLs by calling the <literal>addAuthInfo</literal>
|
|
method of a <literal>CuratorFramework</literal> bean. One way to accomplish this is to provide your own
|
|
<literal>CuratorFramework</literal> bean, as shown in the following example:</simpara>
|
|
<programlisting language="java" linenumbering="unnumbered">@BoostrapConfiguration
|
|
public class CustomCuratorFrameworkConfig {
|
|
|
|
@Bean
|
|
public CuratorFramework curatorFramework() {
|
|
CuratorFramework curator = new CuratorFramework();
|
|
curator.addAuthInfo("digest", "user:password".getBytes());
|
|
return curator;
|
|
}
|
|
|
|
}</programlisting>
|
|
<simpara>Consult
|
|
<link xl:href="https://github.com/spring-cloud/spring-cloud-zookeeper/blob/master/spring-cloud-zookeeper-core/src/main/java/org/springframework/cloud/zookeeper/ZookeeperAutoConfiguration.java">the ZookeeperAutoConfiguration class</link>
|
|
to see how the <literal>CuratorFramework</literal> bean’s default configuration.</simpara>
|
|
<simpara>Alternatively, you can add your credentials from a class that depends on the existing
|
|
<literal>CuratorFramework</literal> bean, as shown in the following example:</simpara>
|
|
<programlisting language="java" linenumbering="unnumbered">@BoostrapConfiguration
|
|
public class DefaultCuratorFrameworkConfig {
|
|
|
|
public ZookeeperConfig(CuratorFramework curator) {
|
|
curator.addAuthInfo("digest", "user:password".getBytes());
|
|
}
|
|
|
|
}</programlisting>
|
|
<simpara>The creation of this bean must occur during the boostrapping phase. You can register
|
|
configuration classes to run during this phase by annotating them with
|
|
<literal>@BootstrapConfiguration</literal> and including them in a comma-separated list that you set as the
|
|
value of the <literal>org.springframework.cloud.bootstrap.BootstrapConfiguration</literal> property in the
|
|
<literal>resources/META-INF/spring.factories</literal> file, as shown in the following example:</simpara>
|
|
<formalpara>
|
|
<title>resources/META-INF/spring.factories</title>
|
|
<para>
|
|
<screen>org.springframework.cloud.bootstrap.BootstrapConfiguration=\
|
|
my.project.CustomCuratorFrameworkConfig,\
|
|
my.project.DefaultCuratorFrameworkConfig</screen>
|
|
</para>
|
|
</formalpara>
|
|
</section>
|
|
</chapter>
|
|
</book> |