使用zookeeeper实现节点监听

/**
 *
 * @author liulei
 * @since 2020-06-17
 * @see  ZookeeperUtils
 */
public class ZookeeperUtil extends ZookeeperUtils {

	private static Logger logger = LoggerFactory.getLogger(ZookeeperUtil.class);

	/**
	 *  同步创建持久化有序节点
	 *
	 * @param path 节点路径
	 * @param data 数据
	 * @return
	 */
	public static String createSequentialPersistentNode(String path, String data) {
		Assert.hasText(path,"节点路径");
		Assert.hasText(data,"节点数据");
		CuratorFramework client = null;
		try {
			// 获取池中对象
			client = ZookeeperClientPool.getInstance().borrowObject();
			return client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT_SEQUENTIAL).forPath(path, data.getBytes());
		} catch (Exception e) {
			logger.error(String.format("同步创建持久化有序节点[%s]错误", path), e);
			throw new BizException(ErrorCode.ZK_CLIENT_OP_ERROR_CODE, String.format("同步创建持久化有序节点[%s]错误", path));
		} finally {
			// 归还池中对象
			ZookeeperClientPool.getInstance().returnObject(client);
		}
	}


	/**
	 *  同步创建临时节点(会话断开连接节点失效)
	 *
	 * @param path 节点路径
	 * @param data 数据
	 * @return
	 */
	public static String createEphemeralNode(String path, String data) {
		Assert.hasText(path,"节点路径");
		Assert.hasText(data,"节点数据");
		CuratorFramework client = null;
		try {
			// 获取池中对象
			client = ZookeeperClientPool.getInstance().borrowObject();
			return client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath(path, data.getBytes());
		} catch (Exception e) {
			logger.error(String.format("创建临时节点[%s]错误", path), e);
			throw new BizException(ErrorCode.ZK_CLIENT_OP_ERROR_CODE, String.format("创建临时节点[%s]错误", path));
		} finally {
			// 归还池中对象
			ZookeeperClientPool.getInstance().returnObject(client);
		}
	}

	/**
	 *   同步创建临时有序节点(会话断开连接节点失效)
	 *
	 * @param path 节点路径
	 * @param data 数据
	 * @return
	 */
	public static String createSequentialEphemeralNode(String path, String data) {
		Assert.hasText(path,"节点路径");
		Assert.hasText(data,"节点数据");
		CuratorFramework client = null;
		try {
			// 获取池中对象
			client = ZookeeperClientPool.getInstance().borrowObject();
			return client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(path, data.getBytes());
		} catch (Exception e) {
			logger.error(String.format("创建临时节点[%s]错误", path), e);
			throw new BizException(ErrorCode.ZK_CLIENT_OP_ERROR_CODE, String.format("创建临时节点[%s]错误", path));
		} finally {
			// 归还池中对象
			ZookeeperClientPool.getInstance().returnObject(client);
		}
	}

	/**
	 *  同步更新数据
	 *
	 * @param path
	 * @param data
	 */
	public static void updateData(String path, String data) {
		Assert.hasText(path,"节点路径");
		Assert.hasText(data,"节点数据");
		CuratorFramework client = null;
		try {
			// 获取池中对象
			client = ZookeeperClientPool.getInstance().borrowObject();
			client.setData().forPath(path, null == data ? null : data.getBytes());
		} catch (Exception e) {
			logger.error(String.format("更新节点数据[%s]错误", path), e);
			throw new BizException(ErrorCode.ZK_CLIENT_OP_ERROR_CODE, String.format("更新节点数据[%s]错误", path));
		} finally {
			// 归还池中对象
			ZookeeperClientPool.getInstance().returnObject(client);
		}
	}


	/**
	 * 同步强制删除一个zookeeper节点同时递归删除子节点
	 *
	 * @param path
	 */
	public static void deleteAllNode(String path){
		Assert.hasText(path,"节点路径");
		CuratorFramework client = null;
		try {// 获取池中对象
			client = ZookeeperClientPool.getInstance().borrowObject();
			client.delete().guaranteed().deletingChildrenIfNeeded().forPath(path);
		} catch (Exception e) {
			logger.error(String.format("删除节点[%s]错误", path), e);
			throw new BizException(ErrorCode.ZK_CLIENT_OP_ERROR_CODE, String.format("删除节点[%s]错误", path));
		} finally {
			// 归还池中对象
			ZookeeperClientPool.getInstance().returnObject(client);
		}
	}

	/**
	 * 同步获取节点的所有子节点
	 *
	 * @param path
	 * @return 返回所有子节点的节点名
	 */
	public static List<String> getChildren(String path){
		Assert.hasText(path,"节点路径");
		CuratorFramework client = null;
		try {
			// 获取池中对象
			client = ZookeeperClientPool.getInstance().borrowObject();
			return client.getChildren().forPath(path);
		} catch (Exception e) {
			logger.error(String.format("获取节点下的子节点[%s]错误", path), e);
			throw new BizException(ErrorCode.ZK_CLIENT_OP_ERROR_CODE, String.format("获取节点下的子节点[%s]错误", path));
		} finally {
			// 归还池中对象
			ZookeeperClientPool.getInstance().returnObject(client);
		}
	}
	/**
	 * 对指定节点进行监听
	 *
	 * @param path 节点路径
	 * @return
	 */
	public  static NodeCache registerNodeCacheListener(String path){
		Assert.hasText(path,"节点路径");
		CuratorFramework client = null;
		try {
			// 获取池中对象
			client = ZookeeperClientPool.getInstance().borrowObject();
			NodeCache nodeCache = new NodeCache(client, path);
			nodeCache.getListenable().addListener(new NodeCacheListener(){
				@Override
				public void nodeChanged() throws Exception {
					logger.info("节点{}成功监听节点数据变化",path);
				}
			});
			nodeCache.start();
			return nodeCache;
		} catch (Exception e) {
			logger.error(String.format("对指定节点进行监听[%s]错误", path), e);
			throw new BizException(ErrorCode.ZK_CLIENT_OP_ERROR_CODE, String.format("对指定节点进行监听[%s]错误", path));
		} finally {
			// 归还池中对象
			ZookeeperClientPool.getInstance().returnObject(client);
		}
	}

	/**
	 * 对指定路径节点的一级子目录监听,不对该节点的操作监听
	 *
	 * @param path
	 * @param listener
	 * @return
	 */
	public static PathChildrenCache registerPathChildListener(String path, PathChildrenCacheListener listener){
		Assert.hasText(path,"节点路径");
		CuratorFramework client = null;
		try {
			// 获取池中对象
			client = ZookeeperClientPool.getInstance().borrowObject();
			PathChildrenCache pathChildrenCache = new PathChildrenCache(client, path,true);
			pathChildrenCache.getListenable().addListener(listener);
			pathChildrenCache.start(PathChildrenCache.StartMode.BUILD_INITIAL_CACHE);
			return pathChildrenCache;
		} catch (Exception e) {
			logger.error(String.format("对指定路径节点的一级子目录监听[%s]错误", path), e);
			throw new BizException(ErrorCode.ZK_CLIENT_OP_ERROR_CODE, String.format("对指定路径节点的一级子目录监听[%s]错误", path));
		}finally {
			// 归还池中对象
			ZookeeperClientPool.getInstance().returnObject(client);
		}
	}

	/**
	 * 注册目录监听器
	 *
	 * @param path
	 * @param maxDepth 节点深度
	 * @param listener
	 * @return
	 */
	public static TreeCache registerTreeCacheListener(String path, int maxDepth, TreeCacheListener listener){
		Assert.hasText(path,"节点路径");
		CuratorFramework client = null;
		try {
			TreeCache treeCache = TreeCache.newBuilder(client,path)
					.setCacheData(true)
					.setMaxDepth(maxDepth)
					.build();
			treeCache.getListenable().addListener(listener);
			treeCache.start();
			return treeCache;
		} catch (Exception e) {
			logger.error(String.format("注册目录监听器[%s]错误", path), e);
			throw new BizException(ErrorCode.ZK_CLIENT_OP_ERROR_CODE, String.format("注册目录监听器[%s]错误", path));
		}finally {
			// 归还池中对象
			ZookeeperClientPool.getInstance().returnObject(client);
		}
	}


}
/**
 * zookeeper节点接听
 *
 * @author liulei
 * @since 2020-06-17
 **/
@Component
public class ZookeeperNodeListener implements InitializingBean, DisposableBean {

    private static final String rootPath = "/";

    private static Logger logger = LoggerFactory.getLogger(ZookeeperNodeListener.class);

    @Autowired
    private TreeCache treeCache;

    @Override
    public void afterPropertiesSet() throws Exception {
        treeCache = ZookeeperUtil.registerTreeCacheListener(rootPath,10,new TreeCacheListener(){
            @Override
            public void childEvent(CuratorFramework client, TreeCacheEvent event) throws Exception {
                try {
                    ChildData childData = event.getData();
                    String path = childData.getPath();
                    String data = new String(childData.getData());
                    data = StringUtils.isBlank(data) ? "" : data;
                    switch (event.getType()) {
                        case NODE_ADDED:
                            logger.info("正在新增子节点路径: {}, 数据:{}",path,data);
                            break;
                        case NODE_UPDATED:
                            logger.info("正在更新子节点: {}, 数据:{}",path,data);
                            break;
                        case NODE_REMOVED:
                            logger.info("正在删除子节点: {}, 数据:{}",path,data);
                            break;
                        case CONNECTION_LOST:
                            logger.info("节点: {}连接丢失",rootPath);
                            break;
                        case CONNECTION_RECONNECTED:
                            logger.info("节点: {}恢复连接",rootPath);
                            break;
                    }
                } catch (Exception e) {
                    logger.error(e.getMessage(),e);
                }
            }
        });
        // 没有中断标记
        while (!Thread.currentThread().isInterrupted()){
            TimeUnit.SECONDS.sleep(1);
        }
    }

    @Override
    public void destroy() throws Exception {
        if(treeCache != null){
            treeCache.close();
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章