使用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();
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章