/**
*
* @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();
}
}
}