zookeeper与Curator存在兼容性问题,官网描述https://curator.apache.org/zk-compatibility-34.html
使用官网方案,自测不行,所以回退到使用Curator 2.x。zookeeper 3.4.x服务器版本与Curator 2.x是兼容的。
一、项目总pom.xml声明版本号
<dependencyManagement>
<dependencies>
<!-- zookeeper -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.14</version>
</dependency>
</dependencies>
</dependencyManagement>
二、项目子模块pom.xml中引入依赖
<dependencies>
<!-- zookeeper -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
</dependency>
</dependencies>
三、zookeeper配置类
/**
* zookeeper配置类
*
* @author
* @date 2021/4/1
*/
@Slf4j
@Configuration
public class ZookeeperConfig {
// @Value("${zookeeper.server}")
private String zkAddress = "127.0.0.1:2181";
@Autowired
DemoService demoService;
/**
* 创建zk客户端,注入spring容器
*
* @return zk客户端
*/
@Bean
public CuratorFramework curatorFramework() {
RetryForever retryForever = new RetryForever(10000);
CuratorFramework client = CuratorFrameworkFactory.builder().connectString(zkAddress).retryPolicy(retryForever).build();
client.getConnectionStateListenable().addListener(new ConnectionStateListener() {
@Override
public void stateChanged(CuratorFramework client, ConnectionState newState) {
if (ConnectionState.RECONNECTED.equals(newState)) {
//重连成功,拉取最新数据同步
log.warn("zk重连成功,同步最新数据。");
client.sync();
}
}
});
client.getCuratorListenable().addListener(new CuratorListener() {
@Override
public void eventReceived(CuratorFramework client, CuratorEvent event) throws Exception {
log.info("zk接收到事件, CuratorEvent={}", event);
}
});
//开启连接
client.start();
log.info("zookeeper 初始化完成...");
//给节点注册监听,可监听到当前节点的多次增删改
NodeCache nodeCache = new NodeCache(client, "zkPath", false);
nodeCache.getListenable().addListener(new NodeCacheListener() {
@Override
public void nodeChanged() throws Exception {
log.info("NodeCache.nodeChanged(),path={}, data={}", nodeCache.getCurrentData().getPath(), new String(nodeCache.getCurrentData().getData()));
//todo 业务处理。。。
//demoService.doWork();
}
});
try {
nodeCache.start(true);
} catch (Exception e) {
log.error("nodeCache start fail, {}", e);
throw new RuntimeException("nodeCache start fail", e);
}
//监听父节点下的所有子节点(可监听多次)
PathChildrenCache pathChildrenCache = new PathChildrenCache(client, "/parentPath", true);
pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
@Override
public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
if (event.getData() == null) {
return;
}
log.info("ZK PathChildrenCache监听到子节点事件,path={}, data={}", event.getData().getPath(), new String(event.getData().getData()));
//todo 业务处理。。。
//demoService.doWork2();
}
});
try {
pathChildrenCache.start();
} catch (Exception e) {
e.printStackTrace();
}
return client;
}
}
四、zookeeper的服务提供类
/**
* Zookeeper服务接口
*
* @author yangzihe
* @date 2021/4/2
*/
public interface ZookeeperService {
/**
* 判断节点是否存在
*/
boolean isExistNode(String path);
/**
* 创建节点
*/
void createNode(CreateMode mode, String path);
/**
* 设置节点数据
*/
void setNodeData(String path, String nodeData);
/**
* 创建/更新节点及其节点数据
*/
void updateNodeAndData(String path, String nodeData);
/**
* 获取节点数据
*/
String getNodeData(String path);
/**
* 获取节点下数据
*/
List<String> getNodeChild(String path);
/**
* 是否递归删除节点
*/
void deleteNode(String path, Boolean recursive);
}
实现类:
/**
* Zookeeper服务接口实现
*
* @author yangzihe
* @date 2021/4/2
*/
@Slf4j
@Service
public class ZookeeperServiceImpl implements ZookeeperService {
@Autowired
private CuratorFramework zkClient;
/**
* 判断节点是否存在
*
* @param path
*
* @return true-存在 false-不存在
*/
@Override
public boolean isExistNode(String path) {
zkClient.sync();
try {
Stat stat = zkClient.checkExists().forPath(path);
return stat != null;
} catch (Exception e) {
log.error("isExistNode error!", e);
throw new RuntimeException("isExistNode error!", e);
}
}
/**
* 创建节点
*
* @param mode
* @param path
*/
@Override
public void createNode(CreateMode mode, String path) {
try {
zkClient.create().creatingParentsIfNeeded().withMode(mode).forPath(path);
} catch (Exception e) {
log.error("createNode error!", e);
throw new RuntimeException("createNode error!", e);
}
}
/**
* 设置节点数据
*
* @param path
* @param nodeData
*/
@Override
public void setNodeData(String path, String nodeData) {
try {
zkClient.setData().forPath(path, nodeData.getBytes("UTF-8"));
} catch (Exception e) {
log.error("setNodeData error!", e);
throw new RuntimeException("setNodeData error!", e);
}
}
/**
* 创建/更新节点及其节点数据
*
* @param path
* @param nodeData
*/
@Override
public void updateNodeAndData(String path, String nodeData) {
try {
if (isExistNode(path)) {
//节点存在
setNodeData(path, nodeData);
} else {
//节点不存在
zkClient.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath(path, nodeData.getBytes("UTF-8"));
}
} catch (Exception e) {
log.error("updateNodeAndData error!", e);
throw new RuntimeException("updateNodeAndData error!", e);
}
}
/**
* 获取节点数据
*
* @param path
*/
@Override
public String getNodeData(String path) {
try {
return new String(zkClient.getData().forPath(path), "UTF-8");
} catch (Exception e) {
log.error("getNodeData error!", e);
throw new RuntimeException("getNodeData error!", e);
}
}
/**
* 获取节点下子节点
*
* @param path
*/
@Override
public List<String> getNodeChild(String path) {
try {
return zkClient.getChildren().forPath(path);
} catch (Exception e) {
log.error("getNodeChild error!", e);
throw new RuntimeException("getNodeChild error!", e);
}
}
/**
* 是否递归删除节点
*
* @param path
* @param recursive
*/
@Override
public void deleteNode(String path, Boolean recursive) {
try {
if (recursive) {
// 递归删除节点,guaranteed()保障机制,若未删除成功,会话有效期内一直尝试删除
zkClient.delete().guaranteed().deletingChildrenIfNeeded().forPath(path);
} else {
// 删除单个节点
zkClient.delete().guaranteed().forPath(path);
}
} catch (Exception e) {
log.error("deleteNode error!", e);
throw new RuntimeException("deleteNode error!", e);
}
}
}