zookeeper-curator的简介和入门案例

1、简介

1.1 什么是 Apache Curator ?

官方给出的解释:

Apache Curator is a Java/JVM client library for Apache ZooKeeper, a distributed coordination service. It includes a highlevel API framework and utilities to make using Apache ZooKeeper much easier and more reliable. It also includes recipes for common use cases and extensions such as service discovery and a Java 8 asynchronous DSL.

大致意思是, Apache CuratorApache Zookeeper 的一个java 客户端,一个分布式协调服务。它包含了高级的 API 框架和工具类,可以让我们使用 Apache Zookeeper更加容易、可靠。还包含了常见的用例和解决方案,比如服务发现和 java 8 异步DSL

1.2 组成

Apache Curator 可以在 Maven 仓库进行下载。其中组件的功能也各不相同。下面介绍一下:

Group ID/org Artifact ID/Name 描述
org.apache.curator curator-recipes 所有的解决方案(食谱)。依赖于curator-client、curator-framework 组件(使用 Maven 时会自动引入)。
org.apache.curator curator-async 具有异步 DSL、 O/R 建模、迁移等功能。
org.apache.curator curator-framework 高级 API 组件。建立在客户端之上,并且会自动将 curator-client 引入。
org.apache.curator curator-client 客户端,用来替换 Zookeeper中的类。
org.apache.curator curator-test 测试:包含TestingServer、Testing群集和其他一些用于测试的工具。
org.apache.curator curator-examples 示例用法。
org.apache.curator curator-x-discovery 服务发现的实现。
org.apache.curator curator-x-discovery-server RESTful 服务器,可以和 Zookeeper 一起使用。

1.3 版本兼容

Zookeeper 3.5.x:Apache Curator 4.0

Zookeeper 3.4.x:使用时必须用低版本 2.x 。如果你要使用 4.0 版本(软兼容模式下),使用 Maven如下,需要排除 zookeeper。

<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>${curator-version}</version>
    <exclusions>
        <exclusion>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
        </exclusion>
    </exclusions>
</dependency>

2、入门案例

1.1 环境准备

本次测试是在 Windows 环境下:

  1. zookeeper 版本是 3.4.14
  2. curator 版本是 2.1.1
  3. 编译环境:jdk 1.8

1.2 pom.xml 文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.feng</groupId>
    <artifactId>zookeeper-curator</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <curator-version>2.11.1</curator-version>
    </properties>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.apache.curator/curator-framework -->
        <!--zookeeper 底层 API 的封装-->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>${curator-version}</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.apache.curator/curator-recipes -->
        <!--
        封装了一些高级特性::Cache事件监听、选举、分布式锁、分布式Barrier
        此处会自动引入框架、客户端依赖
        -->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>${curator-version}</version>
        </dependency>

        <!--日志-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.29</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <!-- Maven 设置编译版本为 jdk 1.8 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
  </project>

1.3 log4j.properties 文件

log4j.rootLogger=WARN, console

log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p %-60c %x - %m%n

1.4 java 类

package org.feng.hello;

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;

/**
 * Created by Feng on 2020/1/16 20:06
 * CurrentProject's name is zookeeper-curator<br>
 * 入门案例:使用 API 连接到 Zookeeper 并创建一个持久结点、存储数据、取出数据并打印。<br>
 * 注意:不要重复执行(zookeeper不会创建同一个名字的结点,会抛出节点已经存在异常)
 * @author Feng
 */
public class CuratorDemo {
    public static void main(String[] args) throws Exception {

        // 重试策略:重试之间等待的初始时间,最大的重试次数
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);

        // 通过工厂建造出连接实例:client
        CuratorFramework client = CuratorFrameworkFactory.builder()
                // 连接地址和端口(zookeeper)
                .connectString("localhost:2181")
                // 会话超时时间
                .sessionTimeoutMs(5000)
                // 连接超时时间
                .connectionTimeoutMs(5000)
                .retryPolicy(retryPolicy)
                .build();

        // 客户端必须开始
        client.start();

        // 在 zookeeper 创建一个结点
        client.create().forPath("/feng2020");
        // 给目标结点存储数据
        client.setData().forPath("/feng2020", "风景搜".getBytes());
        // 取出结点上的数据
        byte[] bytes = client.getData().forPath("/feng2020");
        // 打印数据到控制台
        System.out.println(new String(bytes));

        // 客户端必须关闭
        client.close();
    }
}

3、增删改查案例

CuratorFramework 连接对象的相关练习

注意:

  1. 该对象完全线程安全,可以在集群中共享使用。
  2. 一般使用工厂产生该实例。
  3. 该实例需要使用 start() 启动;并在不使用时,使用 close() 进行关闭。

此部分参考了官方案例:官方案例

3.1 环境准备

与【2、入门案例】保持一致

扫描二维码关注公众号,回复: 9129886 查看本文章

3.2 pom.xml 文件 和 log4j.properties 文件

与【2、入门案例】保持一致

3.3 java 类

3.3.1 CuratorOperator.java

package org.feng.hello;

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.BackgroundCallback;
import org.apache.curator.framework.api.CuratorListener;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.data.Stat;

import java.util.List;

/**
 * Created by Feng on 2020/1/17 9:57
 * CurrentProject's name is zookeeper-curator
 * 核心操作类
 * @author Feng
 */
public class CuratorOperator {

    /**
     * 客户端连接对象
     */
    static CuratorFramework client;

    /**
     * 初始化数据
     */
    private void init(){
        // 重试策略
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);

        // 通过工厂建造出连接实例:client
        client = CuratorFrameworkFactory.builder()
                // 连接地址和端口(zookeeper)
                .connectString("localhost:2181")
                // 会话超时时间
                .sessionTimeoutMs(5000)
                // 连接超时时间
                .connectionTimeoutMs(5000)
                .retryPolicy(retryPolicy)
                .build();
    }

    CuratorOperator() {
        init();
    }

    /**
     * 创建持久结点
     * @param path zookeeper 中的文件路径
     * @param data 数据
     */
    public void create(String path, String data) throws Exception {
        client.create().forPath(path, data.getBytes());
    }

    /**
     * 创建结点:根据结点的模式。如下,
     * <ul>
     *     <li>PERSISTENT:持久结点,客户端断开连接后,不会自动删除</li>
     *     <li>PERSISTENT_SEQUENTIAL:序列持久结点</li>
     *     <li>EPHEMERAL:临时结点,客户端断开连接后,会自动删除</li>
     *     <li>EPHEMERAL_SEQUENTIAL:序列临时结点</li>
     *     <li>CONTAINER:容器结点,有特殊用途。当其中的最后一个被删除时,它也将会成为被删除的候选项</li>
     *     <li>PERSISTENT_WITH_TTL:TTL的持久结点。结点没有在给定的 TTL范围内做出修改,在没有子节点时会被删除</li>
     *     <li>PERSISTENT_SEQUENTIAL_WITH_TTL:TTL的序列化持久结点</li>
     * </ul>
     *
     * @param path zookeeper 中的路径
     * @param data 数据
     * @param mode {@link CreateMode} 中的静态常量
     * @see CreateMode
     */
    public String createWithMode(String path, String data, CreateMode mode) throws Exception {
        return client.create().withProtection().withMode(mode).forPath(path, data.getBytes());
    }


    /**
     * 给指定路径存数据
     * @param path zookeeper 中的路径
     * @param data 数据
     */
    public void setData(String path, String data) throws Exception {
        client.setData().forPath(path, data.getBytes());
    }

    /**
     * 异步设置数据
     * @param path zookeeper 中的路径
     * @param data 数据
     * @see CuratorListener
     */
    public void setDataAsync(String path, String data) throws Exception {
        // 事件或异步通知:监听、检查事件以获取详细信息
        CuratorListener listener = (client1, event) -> System.out.println("事件状态:" + event.getStat());

        // 增加监听
        client.getCuratorListenable().addListener(listener);
        // 设置数据
        client.setData().inBackground().forPath(path, data.getBytes());
    }

    /**
     * 回调设置数据
     */
    public void setDataAsyncWithCallback(BackgroundCallback callback, String path,
                                         String data) throws Exception {
        client.setData().inBackground(callback).forPath(path, data.getBytes());
    }

    /**
     * 删除指定节点(文件)
     * @param path zookeeper 中的路径
     */
    public void delete(String path) throws Exception {
        client.delete().forPath(path);
    }

    /**
     * 删除:保证会执行。<br>
     * 若删除失败,会抛出异常信息。但是,会一直尝试删除,直到成功删除。
     * @param path zookeeper 中的路径
     */
    public void guartanteedDelete(String path) throws Exception {
        client.delete().guaranteed().forPath(path);
    }

    /**
     * 获取子节点,并设置 watcher 在节点上。
     * @param path zookeeper 上的路径
     * @param watcher {@link Watcher}
     */
    public List<String> watchedGetChildren(String path, Watcher watcher) throws Exception {
        return client.getChildren().usingWatcher(watcher).forPath(path);
    }

    /**
     * 获取子节点,并设置 watcher 在节点上。观察者通知时会通过监听
     */
    public List<String> watchedGetChildren(String path) throws Exception {
        return client.getChildren().watched().forPath(path);
    }

    /**
     * 获取数据
     * @param path 指定一个 zookeeper 的结点
     * @return 数据
     */
    public String getData(String path) throws Exception {
        return new String(client.getData().forPath(path));
    }


    /**
     * 判断节点是否存在
     * @param path 节点所在路径
     * @return 存在目标节点时返回一个 {@link Stat};否则返回 null
     */
    public Stat nodeExist(String path) throws Exception {
        return client.checkExists().forPath(path);
    }
}

3.3.2 CuratorOperatorTest.java

package org.feng.hello;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import java.util.UUID;

/**
 * Created by Feng on 2020/1/17 11:00
 * CurrentProject's name is zookeeper-curator
 * 测试:增加节点、修改数据、删除节点、获取数据
 */
public class CuratorOperatorTest {
    private CuratorOperator operator;
    private String path;

    @Before
    public void init(){
        operator = new CuratorOperator();
        // 客户端必须开始
        CuratorOperator.client.start();
        // 获取一个路径
        path = "/" + UUID.randomUUID();
    }


    /**
     * 创建 和 删除
     */
    @Test
    public void createAndDeleteTest() throws Exception {
        // 创建一个节点
        operator.create(path, "小冯同学");
        // 判空:通过测试即节点存在
        Assert.assertNotNull(operator.nodeExist(path));

        // 获取数据
        Assert.assertEquals("小冯同学", operator.getData(path));

        // 改值
        operator.setData(path, "小王");
        // 获取数据
        Assert.assertEquals("小王", operator.getData(path));

        // 删除
        operator.delete(path);
        // 判空:通过测试即节点不存在
        Assert.assertNull(operator.nodeExist(path));
    }
    
    
    @After
    public void close(){
        CuratorOperator.client.close();
    }
}

3.4 事务操作

请参考:官方案例

发布了108 篇原创文章 · 获赞 117 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/FBB360JAVA/article/details/104017549