zookeeper配置代码实现

package com.msb.zk.ZkTest;
import org.apache.zookeeper.ZooKeeper;
import java.util.concurrent.CountDownLatch;
/**
 * @author lcc
 * @version V1.0
 * @Package com.msb.zk.ZkTest
 * @date 2022/4/22 10:30
 */
/*
获得zk
*/
public class ZkUtils {
    private static ZooKeeper zk;
    private static String address="192.168.1.136:2181,192.168.1.137:2181,192.168.1.138:2181,192.168.1.139:2181/testConf";
    private static DefaultWatch watch=new DefaultWatch();

    private static CountDownLatch init= new CountDownLatch(1);//这里定义计数器 是为了防止直接return zk 因为还没有去链接zk 就直接返回了
    //什么时候去减?  再connected 之后再去减
    public static ZooKeeper getZk(){
        //这里new zk 的时候需要传入一个watch
        try {
            zk = new ZooKeeper(address,1000,watch);
            //这里还有一个异步的操作 是去链接 创建session 的统一视图的过程
            //在减之前设置 将init 穿过去让defaultwatch 执行--操作
            watch.setCc(init);
            init.await();//阻塞等待 CountDownLatch为0  可用了 再执行return
            System.out.println("阻塞解除,已成功链接");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return zk;

    }
}
package com.msb.zk.ZkTest;

import org.apache.zookeeper.AsyncCallback;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;

import java.util.concurrent.CountDownLatch;

/**
 * @author lcc
 * @version V1.0
 * @Package com.msb.zk.ZkTest
 * @date 2022/4/22 10:59
 */
public class WatchCallBack implements Watcher, AsyncCallback.StatCallback, AsyncCallback.DataCallback {
    //因为 判断是否存在时需要watcher 和statCallback   而getData 需要Watcher 和dataCallBack
    ZooKeeper zk;
    MyConf conf;
    CountDownLatch cc= new CountDownLatch(1);

    public MyConf getConf() {
        return conf;
    }

    public void setConf(MyConf conf) {
        this.conf = conf;
    }

    public ZooKeeper getZk() {
        return zk;
    }

    public void setZk(ZooKeeper zk) {
        this.zk = zk;
    }


    public  void aWait(){
        //如果就这样的话还是 直接异步  就结束了 获取不到值 需要阻塞 就需要引入CountDownLatch
        zk.exists("/AppConf", this,this , "oldData");
        try {
            cc.await();//等待 数据返回  节点数据存在 且数据取完了
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void processResult(int i, String s, Object o, byte[] data, Stat stat) {
        //判断存在后再执行获取数据
        if(data!=null){
            //取到数据了
            String s1 = new String(data);
            //将从zk获取到的data 数据 转换成字符串 然后通过conf类接受 kafka 传过来的数据
            conf.setConf(s1);//说明取到数据了
            cc.countDown();//这里可以释放线程阻塞
        }
    }

    @Override
    public void processResult(int i, String s, Object o, Stat stat) {
        //状态  判断是否存在
        if(stat!=null){
            //如果状态不为空说明 有数据 那么就可以取数据
            zk.getData("/AppConf", this, this, "AAA");
        }
    }

    @Override
    public void process(WatchedEvent watchedEvent) {
        //节点发生变化的环节 修改
        switch (watchedEvent.getType()) {
            case None:
                break;
            case NodeCreated:
                System.out.println("节点数据创建");
                zk.getData("/AppConf", this, this, "AAA");
                break;
            case NodeDeleted:
                System.out.println("节点数据被删除");
               conf.setConf("");
               //当删除时 设置conf 内容是空
               cc=new CountDownLatch(1);
               //这里重新设置计数器为1 等待文件被创建后减一之后 释放阻塞线程
                break;
            case NodeDataChanged:
                System.out.println("节点数据变更");
                zk.getData("/AppConf", this, this, "AAA");
                break;
            case NodeChildrenChanged:
                break;
        }


    }



}
package com.msb.zk.ZkTest;

import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;

import java.util.concurrent.CountDownLatch;

/**
 * @author lcc
 * @version V1.0
 * @Package com.msb.zk.ZkTest
 * @date 2022/4/22 10:36
 */
public class DefaultWatch implements Watcher {

    CountDownLatch cc;
    //这里引用CountDownLatch 是为了链接成功之后减一 就可以方形那边的阻塞await方法

    public void setCc(CountDownLatch cc) {
        this.cc = cc;
    }

    //这个default watch  是创建zk 使用的watch  与session 有关
    @Override
    public void process(WatchedEvent watchedEvent) {

        System.out.println(watchedEvent.toString());
        //这里是watch 监听zk 的事件
        switch (watchedEvent.getState()) {
            case Unknown:
                break;
            case Disconnected:
                break;
            case NoSyncConnected:
                break;
            case SyncConnected:
                //在connected 之后才能执行减1 操作
                cc.countDown();
                break;
            case AuthFailed:
                break;
            case ConnectedReadOnly:
                break;
            case SaslAuthenticated:
                break;
            case Expired:
                break;
        }



    }
}
package com.msb.zk.ZkTest;

/**
 * @author lcc
 * @version V1.0
 * @Package com.msb.zk.ZkTest
 * @date 2022/4/22 11:12
 */
/*这个类才是你最关心的地方
这里可能不止是放入的是字符串 可能是json  可能是xml
* */
public class MyConf {


    private String conf;

    public String getConf() {
        return conf;
    }

    public void setConf(String conf) {
        this.conf = conf;
    }
}
package com.msb.zk.ZkTest;

import org.apache.zookeeper.ZooKeeper;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

/**
 * @author lcc
 * @version V1.0
 * @Package com.msb.zk.ZkTest
 * @date 2022/4/22 10:29
 */

/*
* 获得zk
* 使用zk
* 断开zk

测试
 */

public class TestConfig {
    ZooKeeper zk;


    @Before
    public  void conn(){

        //先执行这里的方法  设置zk
         zk = ZkUtils.getZk();


    }



    @After
    public void close(){
        try {
            zk.close();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }


    @Test
    public void getConf() throws InterruptedException {
        //怎么去取?  目录是否存在  先判断目录是否存在  如果存在  一定会执行回调方法  那么就可以执行取得操作
        //因为我们在判断是否存在的时候 需要写两个watcher  和 callback 都是匿名内部类 而且 有数据后 执行取操作时 zk.getData 还有匿名内部类
        //所以用一个工具类替代  简化代码
        WatchCallBack watchCallBack=new WatchCallBack();
        //将这里的zk 传过去
        watchCallBack.setZk(zk);
        //因为这是异步的方式  这里 不会阻塞 不会的等待callback返回的值 继续向下走
        //另外一个 watchcall back 的获取到的数据怎么让这个线程知道   那么我们需要创建一个接受数据的类
        MyConf myConf = new MyConf();
        //需要让WatchCallBack 接受数据
        watchCallBack.setConf(myConf);
        //如果myconf 数据更新或者修改了 watchCallBack能取到结果  能获取到kafka传递过来的结果

        //注意zk.exists 是异步的 如果不阻塞 那么会执行下面的方法 获取的值是空
        //只有执行了callBack里面获取到值了才能继续向下走
        watchCallBack.aWait();//这里我们将方法定义在watchCallBack里面的方法里  如果获得到数据 往下走 如果还没获取到数据 就在这里阻塞着

        /*1节点不存在
        虽然会执行getstat 但是状态为空  无法取到数据  那么就会一直阻塞 一直监听是否存在数据
        //一旦创建一个节点 该节点会调用getData 里面的 watcher 和callback
        就会有状态有数据了 线程不阻塞了
        2节点存在
        * */
        while (true){

            if(myConf.getConf().equals("")){
                System.out.println("conf diu le ");
                watchCallBack.aWait();//这里如果conf 内容为空说明文件被删除 那么久应该阻塞,等待文件创建
            }else {
                System.out.println(myConf.getConf());//将watchCallBack里面的数据取出来
            }
            Thread.sleep(200);
        }


    }

}

 

posted @ 2022-04-22 13:31  花心大萝卜li  阅读(93)  评论(0)    收藏  举报