• springBoot 整合 ZooKeeper Java客户端之 Apache Curator 实战


    一、添加项目所需依赖:

       <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
            </dependency>
        
        <!-- Apache Curator 包含了几个包:
                   curator-client:提供一些客户端的操作,例如重试策略等      
          curator-framework:对zookeeper的底层api的一些封装
                   curator-recipes:封装了一些高级特性,如:Cache事件监听、选举、分布式锁、分布式计数器、分布式Barrier等-->
    
            <dependency>
                <groupId>org.apache.curator</groupId>
                <artifactId>curator-recipes</artifactId>
                <version>2.13.0</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-configuration-processor</artifactId>
                <optional>true</optional>
            </dependency>
        </dependencies>                            

    二、连接zooKeeper 服务,使用 Client API:

      1、 application.properties自定义配置: 使用 @ConfigurationProperties 、@EnableConfigurationProperties 注解用来属性映射类

    apache.zookeeper.connect-url=127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183 #连接地址,此地址为单机集群;
    apache.zookeeper.session-timeout=60000 #会话超时时间,默认60000ms
    apache.zookeeper.connection-timeout=15000 #连接创建超时时间,默认15000ms
    apache.zookeeper.scheme=digest #访问控制 验证策略
    apache.zookeeper.auth-id=username:password #权限 Id
    apache.retrypolicy.base-sleep-time=1000 #重连策略,初始化间隔时间 
    apache.retrypolicy.max-retries=3 #重连次数
    apache.retrypolicy.max-sleep=2147483647 #重连最长时间

      2、配置类:

    @ConfigurationProperties(prefix = "apache.zookeeper")
    @Configuration
    public class ApacheZooKeeperProperties {
    
        private String connectUrl;
    
        private int sessionTimeout;
    
        private int connectionTimeout;
    
        private String scheme;
    
        private String authId;
    
    
        public String getConnectUrl() {
            return connectUrl;
        }
    
        public void setConnectUrl(String connectUrl) {
            this.connectUrl = connectUrl;
        }
    
        public int getSessionTimeout() {
            return sessionTimeout;
        }
    
        public void setSessionTimeout(int sessionTimeout) {
            this.sessionTimeout = sessionTimeout;
        }
    
        public int getConnectionTimeout() {
            return connectionTimeout;
        }
    
        public void setConnectionTimeout(int connectionTimeout) {
            this.connectionTimeout = connectionTimeout;
        }
    
        public String getScheme() {
            return scheme;
        }
    
        public void setScheme(String scheme) {
            this.scheme = scheme;
        }
    
        public String getAuthId() {
            return authId;
        }
    
        public void setAuthId(String authId) {
            this.authId = authId;
        }
    }
    @ConfigurationProperties(prefix = "apache.retrypolicy")
    @Configuration
    public class ApacheRetryPolicy {
    
        private int baseSleepTime = 1000;
    
        private int maxRetries = 29;
    
        private int maxSleep = 2147483647;
    
        public int getBaseSleepTime() {
            return baseSleepTime;
        }
    
        public void setBaseSleepTime(int baseSleepTime) {
            this.baseSleepTime = baseSleepTime;
        }
    
        public int getMaxRetries() {
            return maxRetries;
        }
    
        public void setMaxRetries(int maxRetries) {
            this.maxRetries = maxRetries;
        }
    
        public int getMaxSleep() {
            return maxSleep;
        }
    
        public void setMaxSleep(int maxSleep) {
            this.maxSleep = maxSleep;
        }
    }

      3、演示代码:

    /**
     * 演示 Apache Curator API
     * 1、增删查改
     * 2、ACL 访问权限控制
     * 3、注册 watch 事件的三个接口
     */
    @RestController
    public class CuratorClientApiText {
    
        private Logger logger = LoggerFactory.getLogger(CuratorClientApiText.class);
    
        @Autowired
        private CuratorFramework zkClient;
    
        @Autowired
        private ApacheZooKeeperProperties apacheZooKeeperProperties;
    
        private String userParentPath = "/user";
    
        private String userPersistent = "/user/persistent";
    
        private String userEphemeral = "/ephemeral";
    
        private String userPersistentSequential = "/user/persistent_sequential";
    
        private String userEphemeralSequential = "/ephemeral_sequential";
    
        private String result = "";
    
    
        /**
         * Curator API 是链式调用风格,遇到 forPath 接口就触发ZooKeeper 调用
         *
         * 将演示创建 ZooKeeper 四种数据模型
         *
         * @return
         */
        @GetMapping("/create/node")
        public String createNode(){
    
            try {
                //添加 acl 用户
                List<ACL> aclList  = new ArrayList<>();
                aclList.add(new ACL(ZooDefs.Perms.ALL, new Id(apacheZooKeeperProperties.getScheme(), DigestAuthenticationProvider.generateDigest(apacheZooKeeperProperties.getAuthId()))));
    
                /**
                 * CuratorListener监听,此监听主要针对background通知和错误通知;
                 * 使用 watched() 只会观察一次,只对该节点本身 create、delete、setData 有效;
                 * 使用 inBackground() 会异步监听到返回信息,一旦使用该接口,就不会有返回值
                 */
                zkClient.getCuratorListenable().addListener(new CuratorListenerImpl());
    
                /**
                 * NodeCache可以监听节点本身创建、删除,以及内容的变化,但对于子节点的变化不会监听
                 */
                NodeCache nodeCache = new NodeCache(zkClient,userParentPath);
                NodeCacheListenerImpl nodeCacheListener = new NodeCacheListenerImpl();
                nodeCacheListener.setNodeCache(nodeCache);
                nodeCache.start(true); // 设置为 true 把该节点数据存储到本地
                nodeCache.getListenable().addListener(nodeCacheListener);
    
                /**
                 * PathChildrenCache用于监听所有子节点的变化
                 */
                PathChildrenCache pathChildrenCache = new PathChildrenCache(zkClient, userParentPath, true);
                /**
                 * StartMode: 初始化方式
                 * POST_INITIALIZED_EVENT : 异步初始化之后触发事件
                 * NORMAL:异步初始化
                 * BUILD_INITIAL_CACHE:同步初始化
                 */
                pathChildrenCache.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);
                pathChildrenCache.getListenable().addListener(new PathChildrenCacheListenerImpl());
    
                // 注册 watch 事件 
                /*Stat stat = zkClient.checkExists()
                        .watched()
                        .forPath(userParentPath);
                logger.info("/userParentPath 路径状态..." + stat);
    
                stat = zkClient.checkExists()
                        .watched()
                        .forPath(userPersistent);
                logger.info("/userPersistent 路径状态..." + stat);
    
                stat = zkClient.checkExists()
                        .watched()
                        .forPath(userEphemeral);
                logger.info("/userEphemeral 路径状态..." + stat);*/
    
                //持久节点 creatingParentContainersIfNeeded() 接口自动递归创建所需节点的父节点
                result = zkClient.create()
                            .creatingParentContainersIfNeeded()
                            .withMode(CreateMode.PERSISTENT)
                            .withACL(aclList)
                            .forPath(userPersistent, "userPersistentData".getBytes());
    
                Thread.sleep(1000 * 5);
                logger.info("持久节点..." + result);
    
                //临时节点 不能有子节点
                result = zkClient.create()
                            .creatingParentContainersIfNeeded()
                            .withMode(CreateMode.EPHEMERAL)
                            .forPath(userEphemeral,"userEphemeralData".getBytes());
    
                Thread.sleep(1000 * 5);
                logger.info("临时节点..." + result);
    
                //持久序列节点
                result = zkClient.create()
                            .creatingParentContainersIfNeeded()
                            .withMode(CreateMode.PERSISTENT_SEQUENTIAL)
                            .forPath(userPersistentSequential,"userPersistentSequentialData".getBytes());
    
                Thread.sleep(1000 * 5);
                logger.info("持久有序节点..." + result);
    
                //临时序列节点
                result = zkClient.create()
                            .creatingParentContainersIfNeeded()
                            .withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
                            .forPath(userEphemeralSequential,"userEphemeralSequentialData".getBytes());
    
                Thread.sleep(1000 * 5);
                logger.info("临时有序节点..." + result);
            }catch(Exception e){
                logger.info("创建节点失败...");
                e.printStackTrace();
            }
    
            return "curator api 创建节点";
        }
    
        @GetMapping("/node/children")
        public String nodeChildren(){
            try{
                Stat stat = zkClient.checkExists().watched().forPath(userParentPath);
                Thread.sleep(1000 * 5);
                logger.info("判断节点是否存在..." + stat);
    
                List<String> userPaths =  zkClient.getChildren().forPath(userParentPath);
                Thread.sleep(1000 * 5);
                logger.info("获取所有子节点..." + userPaths);
    
            }catch(Exception e){
                logger.info("失败...");
                e.printStackTrace();
            }
    
            return "curator api 获取所有子节点";
        }
    
        @GetMapping("/data/node")
        public String dataNode(){
            try{
                //获取一个节点的内容
                byte[] bytes = zkClient.getData().forPath(userPersistent);
                Thread.sleep(1000 * 5);
                logger.info("获取节点数据..." + new String(bytes));
    
                //修改一个节点的内容
                Stat stat = zkClient.setData().forPath(userPersistent, "updateUserPersistentData".getBytes());
                Thread.sleep(1000 * 5);
                logger.info("修改节点数据..." + stat);
    
            }catch(Exception e){
                logger.info("失败...");
                e.printStackTrace();
            }
            return "curator api 获取、修改节点数据";
        }
    
        @GetMapping("/delete/node")
        public String deleteNode(){
            try{
    
                //删除一个节点,强制指定版本进行删除
                Stat stat = new Stat();
                zkClient.getData().storingStatIn(stat).forPath(userPersistent);
                zkClient.delete().withVersion(stat.getVersion()).forPath(userPersistent);
                Thread.sleep(1000 * 5);
    
                //删除一个节点,并且递归删除其所有子节点
                zkClient.delete().deletingChildrenIfNeeded().forPath(userParentPath);
                Thread.sleep(1000 * 5);
    
            }catch(Exception e){
                logger.info("删除节点失败...");
                e.printStackTrace();
            }
    
            return "curator api 删除节点";
        }
    
    }
    /**
     * 连接zooKeeper server,获得zkClient
     */
    @Configuration
    @EnableConfigurationProperties(value = {ApacheZooKeeperProperties.class, ApacheRetryPolicy.class})
    public class ApacheCuratorConfig {
    
        private Logger logger = LoggerFactory.getLogger(ApacheCuratorConfig.class);
    
        @Autowired
        private ApacheZooKeeperProperties apacheZooKeeperProperties;
    
        @Autowired
        private ApacheRetryPolicy apacheRetryPolicy;
    
        CuratorFramework client = null;
    
        @Bean
        public CuratorFramework getCuratorFramework(){
            logger.info("zooKeeper client init...");
    
            try {
                //当zk连接时失败的重连策略
                RetryPolicy retryPolicy = new ExponentialBackoffRetry(apacheRetryPolicy.getBaseSleepTime(), apacheRetryPolicy.getMaxRetries());
    
                //获得实例对象,拿到ZK client
                //CuratorFramework client = CuratorFrameworkFactory.newClient(apacheZooKeeperProperties.getConnectUrl(), apacheZooKeeperProperties.getSessionTimeout(), apacheZooKeeperProperties.getConnectionTimeout(), retryPolicy);
                List<AuthInfo> authInfos = new ArrayList<>();
                authInfos.add(new AuthInfo(apacheZooKeeperProperties.getScheme(), apacheZooKeeperProperties.getAuthId().getBytes()));
    
                client = CuratorFrameworkFactory.builder()
                        .authorization(authInfos)
                        .connectString(apacheZooKeeperProperties.getConnectUrl())
                        .sessionTimeoutMs(apacheZooKeeperProperties.getSessionTimeout())
                        .connectionTimeoutMs(apacheZooKeeperProperties.getConnectionTimeout())
                        .retryPolicy(retryPolicy)
                        .namespace("workspace")
                        .build();
    
                client.start();
                logger.info("zooKeeper client start...");
    
            }catch (Exception e){
                logger.info("zooKeeper connect error...");
                e.printStackTrace();
            }
            return client;
        }
    } 
  • 相关阅读:
    ActiveMQ的用途
    HTTP 状态码的完整列表
    Linux中脚本运行错误(坏的解释器:没有那个文件或目录)
    Linux下ping: unknown host www.baidu.com的解决办法
    python中的collection
    Table里嵌套ASPXGridView
    致2015
    WPF学习之Binding(二)
    WPF学习之Binding(一)
    WPF UI布局(Layout)
  • 原文地址:https://www.cnblogs.com/haiyangwu/p/10370871.html
Copyright © 2020-2023  润新知