zookeeper 永久监听节点 来保证集群间一致性

先是封装的 zkClient

 

 
public class ZkClient {

    public Logger logger = LoggerFactory.getLogger(getClass());
    public ZooKeeper zookeeper;
    private static int SESSION_TIME_OUT = 2000;
    private IWatchEvent watchEvent;
    private static CountDownLatch countDownLatch = new CountDownLatch(1);
    private SessionWatcher sessionWatcher = new SessionWatcher();

    public ZkClient(){

    }

    public ZkClient(IWatchEvent we){
        this.watchEvent = we;
    }


    /**
     * 连接zookeeper
     * @param host
     * @throws IOException
     * @throws InterruptedException
     */
    public void connectZookeeper(String host){
        logger.info(Log.op("连接ZooKeeper开始").kv("host:", host).toString());
        try {
            zookeeper = new ZooKeeper(host, SESSION_TIME_OUT, sessionWatcher);
            //连接超时4S
            countDownLatch.await(4000, TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            logger.error(Log.op("连接ZooKeeper异常").kv("host:", host).toString(), e);
        }
        logger.info(Log.op("连接ZooKeeper完成").kv("host:", host).toString());
    }

    class SessionWatcher implements Watcher {

        public void process(WatchedEvent watchedEvent) {
            logger.info(Log.op("zookeeper事件")
                    .kv("state:", watchedEvent.getState()).kv("type:", watchedEvent.getType()).toString());
            if(watchedEvent.getState() == Event.KeeperState.SyncConnected){
                countDownLatch.countDown();
            }

            if (watchEvent != null){
                watchEvent.watchAfter(watchedEvent);
            }

        }

    }

    /**
     * 根据路径创建节点,并且设置节点数据
     * @param path
     * @param data
     * @return
     * @throws KeeperException
     * @throws InterruptedException
     */
    public String createNode(String path,byte[] data){
        logger.info(Log.op("创建ZooKeeper节点").kv("nodePath:", path).kv("data:", data).toString());
        String s = null;
        try {
            s = this.zookeeper.create(path, data, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        } catch (Exception e) {
            logger.error(Log.op("创建ZooKeeper节点异常").kv("nodePath:", path).kv("data:", data).toString(), e);
        }
        return s;
    }

    /**
     * 节点是否存在
     * @param path
     * @return
     * @throws KeeperException
     * @throws InterruptedException
     */
    public boolean exists(String path) {
        boolean bl = false;
        try {
            if (this.zookeeper.exists(path, true) != null) {
                bl = true;
            }
        } catch (Exception e) {
            logger.error(Log.op("判断zookeeper节点是否存在异常").toString(), e);

        }
        return bl;
    }

    /**
     * 为节点设置监听
     * @param path
     * @throws KeeperException
     * @throws InterruptedException
     */
    public void existsWatch(String path) {
        try {
            this.zookeeper.exists(path, sessionWatcher);
        } catch (Exception e) {
            logger.error(Log.op("设置ZooKeeper节点监听异常").kv("nodePath:", path).toString(), e);
        }
    }

    /**
     * 关闭zookeeper连接
     * @throws InterruptedException
     */
    public void closeConnect() {
        if(null != zookeeper){
            try {
                zookeeper.close();
            } catch (InterruptedException e) {
                logger.error(Log.op("关闭zookeeper连接异常").toString(), e);
            }
        }
    }

}


只是简单是写了些自己要用到的操作,

 

接口 IWatchEvent 用来在watch事件执行个性化操作

 

public interface IWatchEvent {

    void watchAfter(WatchedEvent watchedEvent);
}

 

 

最后是关键的ZkConfig类

 

@Configuration
public class ZkConfig {

    @Value("${zookeeper.host}")
    private String host;

    @Value("${zookeeper.nodePath.rule}")
    private String nodePath;

    public Logger logger = LoggerFactory.getLogger(getClass());

    private ZkClient client = null;

    @Resource
    DroolsHelperService droolsHelperService;

    class CusWatcherEvent implements IWatchEvent{

        @Override
        public void watchAfter(WatchedEvent watchedEvent) {
            try {
                if (watchedEvent.getType() == Watcher.Event.EventType.NodeDataChanged){
                    logger.info(Log.op("ZooKeeper节点数据变化").kv("nodePath:", nodePath).toString());
                    droolsHelperService.loadRule();
                }
                //失效重连
                if (watchedEvent.getState() == Watcher.Event.KeeperState.Expired) {
                    client.closeConnect();
                    client.connectZookeeper(host);
                }

            } catch (Exception e) {
                logger.error(Log.op("加载规则异常").kv("nodePath:", nodePath).toString(), e);
            }finally {
                logger.info(Log.op("重新监听ZooKeeper节点").kv("nodePath:", nodePath).toString());
                client.existsWatch(nodePath);
            }
        }
    }
    /**
     * 添加zk节点监听
     */
    @PostConstruct
    private void init(){
        client = new ZkClient(new CusWatcherEvent());
        client.connectZookeeper(host);
        byte[] bytes = new byte[]{1};
        if (!client.exists(nodePath)) {
            client.createNode(nodePath, bytes);
        }else{
            logger.info(Log.op("ZooKeeper节点已存在").kv("nodePath:", nodePath).toString());
        }

    }

}

watch 是一次性监听,所以每次都注册新的监听

你可能感兴趣的:(java)